W3 Total Cache - Version 0.9.5.2

Version Description

  • Fixed security issue by protecting configuration data by adding .php to relevant files
  • Fixed security issue with the creation of dot folders that could be abused
  • Fixed handling HTTP compression for uncached pages
  • Fixed handling of .svgz files
  • Added expiration headers to webP images
  • Added support for Microsoft Azures latest API
  • Added ability to cache WP Admin. Recommended setting, is off. (Improved WP Admin performance with object caching enabled)
  • Added HTTP/2 Push support for minified files
  • Added option management support for wp-cli
  • Improved handling of uncompressed minified files
  • Improved handling of purging of modified pages / posts
  • Improved compatibility with Rackspace Cloud Files
  • Improved initial CDN configuration reliability
  • Improved reliability of object caching
  • Improved PHP 7.0 compatibility
  • Improved PHP 4.3 compatibility
  • Improved HTTP/2 support
  • Improved CSS embed handling
  • Improved reliability of object cache, transients now fallback to database
  • Improved handling of cached http compressed objects
Download this release

Release Info

Developer fredericktownes
Plugin Icon 128x128 W3 Total Cache
Version 0.9.5.2
Comparing to
See all releases

Code changes from version 0.9.5.1 to 0.9.5.2

Files changed (232) hide show
  1. BrowserCache_Environment.php +4 -3
  2. BrowserCache_Plugin.php +3 -2
  3. Cache.php +3 -3
  4. Cache_File_Generic.php +11 -11
  5. Cache_Memcache.php +6 -0
  6. Cache_Memcached.php +6 -0
  7. CdnEngine_Azure.php +57 -114
  8. CdnEngine_GoogleDrive.php +9 -1
  9. Cdn_Core.php +1 -1
  10. Cdn_Plugin.php +39 -15
  11. Cdn_RackSpace_Api_CaCert.pem → Cdn_RackSpace_Api_CaCert-example.pem +0 -0
  12. Cdn_RackSpace_Api_Cdn.php +24 -8
  13. Cdn_RackSpace_Api_CloudFiles.php +14 -7
  14. Cdn_RackSpace_Api_CloudFilesCdn.php +12 -5
  15. Cdn_RackSpace_Api_Tokens.php +2 -2
  16. Cdn_Util.php +19 -0
  17. Cli.php +218 -86
  18. Config.php +24 -3
  19. ConfigCompiler.php +43 -8
  20. ConfigKeys.php +24 -3
  21. DbCache_Core.php +4 -4
  22. DbCache_Plugin_Admin.php +4 -4
  23. DbCache_WpdbInjection_QueryCaching.php +6 -5
  24. Dispatcher.php +3 -4
  25. Enterprise_Dbcache_WpdbInjection_Cluster.php +33 -30
  26. Enterprise_SnsServer.php +6 -0
  27. Extension_CloudFlare_Plugin.php +7 -1
  28. Extension_CloudFlare_Plugin_Admin.php +2 -1
  29. Extension_FragmentCache_Plugin_Admin.php +4 -4
  30. Extension_FragmentCache_WpObjectCache.php +4 -4
  31. Extension_Genesis_Plugin.php +1 -0
  32. Extension_NewRelic_Plugin.php +1 -1
  33. Extensions_Plugin_Admin.php +1 -1
  34. Generic_AdminActions_Flush.php +4 -4
  35. Generic_AdminActions_Test.php +13 -13
  36. Generic_ConfigLabels.php +1 -1
  37. Generic_Environment.php +14 -6
  38. Generic_Page_Dashboard.php +1 -1
  39. Generic_Page_General.php +1 -1
  40. Generic_Plugin.php +4 -9
  41. Generic_Plugin_Admin.php +26 -26
  42. Generic_Plugin_AdminNotifications.php +1 -1
  43. Minify_ConfigLabels.php +1 -1
  44. Minify_ContentMinifier.php +9 -9
  45. Minify_Core.php +16 -5
  46. Minify_Environment.php +29 -21
  47. Minify_MinifiedFileRequestHandler.php +34 -42
  48. Minify_Plugin.php +300 -224
  49. Minify_Plugin_Admin.php +5 -5
  50. ObjectCache_Plugin.php +2 -2
  51. ObjectCache_Plugin_Admin.php +4 -4
  52. ObjectCache_WpObjectCache_Regular.php +235 -43
  53. PgCache_ContentGrabber.php +161 -111
  54. PgCache_Plugin.php +1 -1
  55. PgCache_Plugin_Admin.php +14 -13
  56. UsageStatistics_Widget.php +15 -7
  57. UsageStatistics_Widget_View.php +107 -103
  58. Util_Content.php +23 -5
  59. Util_Debug.php +1 -1
  60. Util_Environment.php +49 -40
  61. Util_File.php +47 -4
  62. Util_PageUrls.php +1 -1
  63. Util_Rule.php +0 -17
  64. Util_RuleSnippet.php +1 -1
  65. Util_Ui.php +1 -1
  66. Util_WpFile.php +1 -1
  67. inc/lightbox/self_test.php +0 -9
  68. inc/mime/html.php +1 -1
  69. inc/mime/other.php +1 -0
  70. inc/options/cdn.php +1 -1
  71. inc/options/minify.php +32 -3
  72. inc/options/objectcache.php +13 -0
  73. inc/options/parts/memcached.php +4 -4
  74. inc/options/parts/memcached_extension.php +3 -3
  75. inc/options/parts/redis.php +1 -1
  76. inc/options/pgcache.php +2 -2
  77. languages/faq-pro-en_US.xml +204 -204
  78. languages/w3-total-cache-ar_AR.po +1 -1
  79. languages/w3-total-cache-nl_NL.po +1 -1
  80. languages/w3-total-cache-pl_PL.po +1 -1
  81. languages/w3-total-cache-sr_RS.po +1 -1
  82. lib/Azure/GuzzleHttp/Client.php +408 -0
  83. lib/Azure/GuzzleHttp/ClientInterface.php +84 -0
  84. lib/Azure/GuzzleHttp/Cookie/CookieJar.php +265 -0
  85. lib/Azure/GuzzleHttp/Cookie/CookieJarInterface.php +84 -0
  86. lib/Azure/GuzzleHttp/Cookie/FileCookieJar.php +90 -0
  87. lib/Azure/GuzzleHttp/Cookie/SessionCookieJar.php +71 -0
  88. lib/Azure/GuzzleHttp/Cookie/SetCookie.php +404 -0
  89. lib/Azure/GuzzleHttp/Exception/BadResponseException.php +7 -0
  90. lib/Azure/GuzzleHttp/Exception/ClientException.php +7 -0
  91. lib/Azure/GuzzleHttp/Exception/ConnectException.php +37 -0
  92. lib/Azure/GuzzleHttp/Exception/GuzzleException.php +4 -0
  93. lib/Azure/GuzzleHttp/Exception/RequestException.php +210 -0
  94. lib/Azure/GuzzleHttp/Exception/SeekException.php +27 -0
  95. lib/Azure/GuzzleHttp/Exception/ServerException.php +7 -0
  96. lib/Azure/GuzzleHttp/Exception/TooManyRedirectsException.php +4 -0
  97. lib/Azure/GuzzleHttp/Exception/TransferException.php +4 -0
  98. lib/Azure/GuzzleHttp/Handler/CurlFactory.php +536 -0
  99. lib/Azure/GuzzleHttp/Handler/CurlFactoryInterface.php +27 -0
  100. lib/Azure/GuzzleHttp/Handler/CurlHandler.php +45 -0
  101. lib/Azure/GuzzleHttp/Handler/CurlMultiHandler.php +197 -0
  102. lib/Azure/GuzzleHttp/Handler/EasyHandle.php +92 -0
  103. lib/Azure/GuzzleHttp/Handler/MockHandler.php +176 -0
  104. lib/Azure/GuzzleHttp/Handler/Proxy.php +55 -0
  105. lib/Azure/GuzzleHttp/Handler/StreamHandler.php +490 -0
  106. lib/Azure/GuzzleHttp/HandlerStack.php +273 -0
  107. lib/Azure/GuzzleHttp/MessageFormatter.php +182 -0
  108. lib/Azure/GuzzleHttp/Middleware.php +254 -0
  109. lib/Azure/GuzzleHttp/Pool.php +123 -0
  110. lib/Azure/GuzzleHttp/PrepareBodyMiddleware.php +112 -0
  111. lib/Azure/GuzzleHttp/Promise/AggregateException.php +16 -0
  112. lib/Azure/GuzzleHttp/Promise/CancellationException.php +9 -0
  113. lib/Azure/GuzzleHttp/Promise/Coroutine.php +151 -0
  114. lib/Azure/GuzzleHttp/Promise/EachPromise.php +229 -0
  115. lib/Azure/GuzzleHttp/Promise/FulfilledPromise.php +82 -0
  116. lib/Azure/GuzzleHttp/Promise/Promise.php +273 -0
  117. lib/Azure/GuzzleHttp/Promise/PromiseInterface.php +93 -0
  118. lib/Azure/GuzzleHttp/Promise/PromisorInterface.php +15 -0
  119. lib/Azure/GuzzleHttp/Promise/RejectedPromise.php +87 -0
  120. lib/Azure/GuzzleHttp/Promise/RejectionException.php +47 -0
  121. lib/Azure/GuzzleHttp/Promise/TaskQueue.php +66 -0
  122. lib/Azure/GuzzleHttp/Promise/TaskQueueInterface.php +25 -0
  123. lib/Azure/GuzzleHttp/Promise/functions.php +457 -0
  124. lib/Azure/GuzzleHttp/Promise/functions_include.php +6 -0
  125. lib/Azure/GuzzleHttp/Psr7/AppendStream.php +233 -0
  126. lib/Azure/GuzzleHttp/Psr7/BufferStream.php +137 -0
  127. lib/Azure/GuzzleHttp/Psr7/CachingStream.php +138 -0
  128. lib/Azure/GuzzleHttp/Psr7/DroppingStream.php +42 -0
  129. lib/Azure/GuzzleHttp/Psr7/FnStream.php +149 -0
  130. lib/Azure/GuzzleHttp/Psr7/InflateStream.php +52 -0
  131. lib/Azure/GuzzleHttp/Psr7/LazyOpenStream.php +39 -0
  132. lib/Azure/GuzzleHttp/Psr7/LimitStream.php +155 -0
  133. lib/Azure/GuzzleHttp/Psr7/MessageTrait.php +183 -0
  134. lib/Azure/GuzzleHttp/Psr7/MultipartStream.php +153 -0
  135. lib/Azure/GuzzleHttp/Psr7/NoSeekStream.php +22 -0
  136. lib/Azure/GuzzleHttp/Psr7/PumpStream.php +165 -0
  137. lib/Azure/GuzzleHttp/Psr7/Request.php +142 -0
  138. lib/Azure/GuzzleHttp/Psr7/Response.php +131 -0
  139. lib/Azure/GuzzleHttp/Psr7/ServerRequest.php +346 -0
  140. lib/Azure/GuzzleHttp/Psr7/Stream.php +245 -0
  141. lib/Azure/GuzzleHttp/Psr7/StreamDecoratorTrait.php +149 -0
  142. lib/Azure/GuzzleHttp/Psr7/StreamWrapper.php +121 -0
  143. lib/Azure/GuzzleHttp/Psr7/UploadedFile.php +316 -0
  144. lib/Azure/GuzzleHttp/Psr7/Uri.php +602 -0
  145. lib/Azure/GuzzleHttp/Psr7/functions.php +826 -0
  146. lib/Azure/GuzzleHttp/Psr7/functions_include.php +6 -0
  147. lib/Azure/GuzzleHttp/RedirectMiddleware.php +231 -0
  148. lib/Azure/GuzzleHttp/RequestOptions.php +244 -0
  149. lib/Azure/GuzzleHttp/RetryMiddleware.php +112 -0
  150. lib/Azure/GuzzleHttp/TransferStats.php +126 -0
  151. lib/Azure/GuzzleHttp/UriTemplate.php +241 -0
  152. lib/Azure/GuzzleHttp/functions.php +329 -0
  153. lib/Azure/GuzzleHttp/functions_include.php +6 -0
  154. lib/Azure/MicrosoftAzureStorage/Blob/BlobRestProxy.php +2678 -0
  155. lib/Azure/MicrosoftAzureStorage/Blob/Internal/IBlob.php +502 -0
  156. lib/Azure/MicrosoftAzureStorage/Blob/Models/AccessCondition.php +246 -0
  157. lib/Azure/MicrosoftAzureStorage/Blob/Models/AccessPolicy.php +141 -0
  158. lib/Azure/MicrosoftAzureStorage/Blob/Models/AcquireLeaseOptions.php +66 -0
  159. lib/Azure/MicrosoftAzureStorage/Blob/Models/AcquireLeaseResult.php +88 -0
  160. lib/Azure/MicrosoftAzureStorage/Blob/Models/Blob.php +174 -0
  161. lib/Azure/MicrosoftAzureStorage/Blob/Models/BlobBlockType.php +63 -0
  162. lib/Azure/MicrosoftAzureStorage/Blob/Models/BlobPrefix.php +68 -0
  163. lib/Azure/MicrosoftAzureStorage/Blob/Models/BlobProperties.php +431 -0
  164. lib/Azure/MicrosoftAzureStorage/Blob/Models/BlobServiceOptions.php +65 -0
  165. lib/Azure/MicrosoftAzureStorage/Blob/Models/BlobType.php +42 -0
  166. lib/Azure/MicrosoftAzureStorage/Blob/Models/Block.php +99 -0
  167. lib/Azure/MicrosoftAzureStorage/Blob/Models/BlockList.php +175 -0
  168. lib/Azure/MicrosoftAzureStorage/Blob/Models/BreakLeaseResult.php +86 -0
  169. lib/Azure/MicrosoftAzureStorage/Blob/Models/CommitBlobBlocksOptions.php +258 -0
  170. lib/Azure/MicrosoftAzureStorage/Blob/Models/Container.php +150 -0
  171. lib/Azure/MicrosoftAzureStorage/Blob/Models/ContainerACL.php +218 -0
  172. lib/Azure/MicrosoftAzureStorage/Blob/Models/ContainerProperties.php +95 -0
  173. lib/Azure/MicrosoftAzureStorage/Blob/Models/CopyBlobOptions.php +205 -0
  174. lib/Azure/MicrosoftAzureStorage/Blob/Models/CopyBlobResult.php +123 -0
  175. lib/Azure/MicrosoftAzureStorage/Blob/Models/CreateBlobBlockOptions.php +139 -0
  176. lib/Azure/MicrosoftAzureStorage/Blob/Models/CreateBlobOptions.php +520 -0
  177. lib/Azure/MicrosoftAzureStorage/Blob/Models/CreateBlobPagesOptions.php +122 -0
  178. lib/Azure/MicrosoftAzureStorage/Blob/Models/CreateBlobPagesResult.php +184 -0
  179. lib/Azure/MicrosoftAzureStorage/Blob/Models/CreateBlobSnapshotOptions.php +123 -0
  180. lib/Azure/MicrosoftAzureStorage/Blob/Models/CreateBlobSnapshotResult.php +154 -0
  181. lib/Azure/MicrosoftAzureStorage/Blob/Models/CreateContainerOptions.php +123 -0
  182. lib/Azure/MicrosoftAzureStorage/Blob/Models/DeleteBlobOptions.php +151 -0
  183. lib/Azure/MicrosoftAzureStorage/Blob/Models/DeleteContainerOptions.php +66 -0
  184. lib/Azure/MicrosoftAzureStorage/Blob/Models/GetBlobMetadataOptions.php +122 -0
  185. lib/Azure/MicrosoftAzureStorage/Blob/Models/GetBlobMetadataResult.php +147 -0
  186. lib/Azure/MicrosoftAzureStorage/Blob/Models/GetBlobOptions.php +208 -0
  187. lib/Azure/MicrosoftAzureStorage/Blob/Models/GetBlobPropertiesOptions.php +122 -0
  188. lib/Azure/MicrosoftAzureStorage/Blob/Models/GetBlobPropertiesResult.php +95 -0
  189. lib/Azure/MicrosoftAzureStorage/Blob/Models/GetBlobResult.php +142 -0
  190. lib/Azure/MicrosoftAzureStorage/Blob/Models/GetContainerACLResult.php +145 -0
  191. lib/Azure/MicrosoftAzureStorage/Blob/Models/GetContainerPropertiesResult.php +126 -0
  192. lib/Azure/MicrosoftAzureStorage/Blob/Models/LeaseMode.php +46 -0
  193. lib/Azure/MicrosoftAzureStorage/Blob/Models/ListBlobBlocksOptions.php +187 -0
  194. lib/Azure/MicrosoftAzureStorage/Blob/Models/ListBlobBlocksResult.php +274 -0
  195. lib/Azure/MicrosoftAzureStorage/Blob/Models/ListBlobsOptions.php +237 -0
  196. lib/Azure/MicrosoftAzureStorage/Blob/Models/ListBlobsResult.php +345 -0
  197. lib/Azure/MicrosoftAzureStorage/Blob/Models/ListContainersOptions.php +171 -0
  198. lib/Azure/MicrosoftAzureStorage/Blob/Models/ListContainersResult.php +266 -0
  199. lib/Azure/MicrosoftAzureStorage/Blob/Models/ListPageBlobRangesOptions.php +179 -0
  200. lib/Azure/MicrosoftAzureStorage/Blob/Models/ListPageBlobRangesResult.php +196 -0
  201. lib/Azure/MicrosoftAzureStorage/Blob/Models/PageRange.php +129 -0
  202. lib/Azure/MicrosoftAzureStorage/Blob/Models/PageWriteOption.php +44 -0
  203. lib/Azure/MicrosoftAzureStorage/Blob/Models/PublicAccessType.php +66 -0
  204. lib/Azure/MicrosoftAzureStorage/Blob/Models/SetBlobMetadataOptions.php +95 -0
  205. lib/Azure/MicrosoftAzureStorage/Blob/Models/SetBlobMetadataResult.php +118 -0
  206. lib/Azure/MicrosoftAzureStorage/Blob/Models/SetBlobPropertiesOptions.php +292 -0
  207. lib/Azure/MicrosoftAzureStorage/Blob/Models/SetBlobPropertiesResult.php +149 -0
  208. lib/Azure/MicrosoftAzureStorage/Blob/Models/SetContainerMetadataOptions.php +78 -0
  209. lib/Azure/MicrosoftAzureStorage/Blob/Models/SignedIdentifier.php +103 -0
  210. lib/Azure/MicrosoftAzureStorage/Common/CloudConfigurationManager.php +167 -0
  211. lib/Azure/MicrosoftAzureStorage/Common/Internal/Authentication/IAuthScheme.php +60 -0
  212. lib/Azure/MicrosoftAzureStorage/Common/Internal/Authentication/SharedKeyAuthScheme.php +139 -0
  213. lib/Azure/MicrosoftAzureStorage/Common/Internal/Authentication/StorageAuthScheme.php +213 -0
  214. lib/Azure/MicrosoftAzureStorage/Common/Internal/Authentication/TableSharedKeyLiteAuthScheme.php +121 -0
  215. lib/Azure/MicrosoftAzureStorage/Common/Internal/ConnectionStringParser.php +352 -0
  216. lib/Azure/MicrosoftAzureStorage/Common/Internal/ConnectionStringSource.php +98 -0
  217. lib/Azure/MicrosoftAzureStorage/Common/Internal/FilterableService.php +52 -0
  218. lib/Azure/MicrosoftAzureStorage/Common/Internal/Filters/AuthenticationFilter.php +92 -0
  219. lib/Azure/MicrosoftAzureStorage/Common/Internal/Filters/DateFilter.php +70 -0
  220. lib/Azure/MicrosoftAzureStorage/Common/Internal/Filters/ExponentialRetryPolicy.php +134 -0
  221. lib/Azure/MicrosoftAzureStorage/Common/Internal/Filters/HeadersFilter.php +94 -0
  222. lib/Azure/MicrosoftAzureStorage/Common/Internal/Filters/RetryPolicy.php +66 -0
  223. lib/Azure/MicrosoftAzureStorage/Common/Internal/Filters/RetryPolicyFilter.php +106 -0
  224. lib/Azure/MicrosoftAzureStorage/Common/Internal/Http/HttpCallContext.php +449 -0
  225. lib/Azure/MicrosoftAzureStorage/Common/Internal/HttpFormatter.php +52 -0
  226. lib/Azure/MicrosoftAzureStorage/Common/Internal/IServiceFilter.php +61 -0
  227. lib/Azure/MicrosoftAzureStorage/Common/Internal/InvalidArgumentTypeException.php +57 -0
  228. lib/Azure/MicrosoftAzureStorage/Common/Internal/Logger.php +83 -0
  229. lib/Azure/MicrosoftAzureStorage/Common/Internal/Resources.php +404 -0
  230. lib/Azure/MicrosoftAzureStorage/Common/Internal/RestProxy.php +162 -0
  231. lib/Azure/MicrosoftAzureStorage/Common/Internal/RetryMiddlewareFactory.php +234 -0
  232. lib/Azure/MicrosoftAzureStorage/Common/Internal/Serialization/ISerializer.php +68 -0
BrowserCache_Environment.php CHANGED
@@ -315,9 +315,6 @@ class BrowserCache_Environment {
315
  $rules .= " BrowserMatch \\bMSI[E] !no-gzip !gzip-only-text/html\n";
316
  $rules .= " </IfModule>\n";
317
  }
318
- $rules .= " <IfModule mod_headers.c>\n";
319
- $rules .= " Header append Vary User-Agent env=!dont-vary\n";
320
- $rules .= " </IfModule>\n";
321
  if ( version_compare( $this->_get_server_version(), '2.3.7', '>=' ) ) {
322
  $rules .= " <IfModule mod_filter.c>\n";
323
  }
@@ -393,6 +390,10 @@ class BrowserCache_Environment {
393
  $rules = '';
394
  $headers_rules = '';
395
 
 
 
 
 
396
  if ( $cache_control ) {
397
  $cache_policy = $config->get_string( 'browsercache.' . $section . '.cache.policy' );
398
 
315
  $rules .= " BrowserMatch \\bMSI[E] !no-gzip !gzip-only-text/html\n";
316
  $rules .= " </IfModule>\n";
317
  }
 
 
 
318
  if ( version_compare( $this->_get_server_version(), '2.3.7', '>=' ) ) {
319
  $rules .= " <IfModule mod_filter.c>\n";
320
  }
390
  $rules = '';
391
  $headers_rules = '';
392
 
393
+ if ( $section == 'html' ) {
394
+ $headers_rules .= " Header append Vary User-Agent env=!dont-vary\n";
395
+ }
396
+
397
  if ( $cache_control ) {
398
  $cache_policy = $config->get_string( 'browsercache.' . $section . '.cache.policy' );
399
 
BrowserCache_Plugin.php CHANGED
@@ -115,7 +115,7 @@ class BrowserCache_Plugin {
115
  * @return mixed
116
  */
117
  function ob_callback( $buffer ) {
118
- if ( $buffer != '' && Util_Content::is_html( $buffer ) ) {
119
  $domain_url_regexp = Util_Environment::home_domain_root_url_regexp();
120
 
121
  $buffer = preg_replace_callback(
@@ -214,7 +214,8 @@ class BrowserCache_Plugin {
214
 
215
  $test_url = Util_Environment::remove_query( $url );
216
  foreach ( $exceptions as $exception ) {
217
- if ( trim( $exception ) && preg_match( '~' . $exception . '~', $test_url ) )
 
218
  return false;
219
  }
220
 
115
  * @return mixed
116
  */
117
  function ob_callback( $buffer ) {
118
+ if ( $buffer != '' && Util_Content::is_html_xml( $buffer ) ) {
119
  $domain_url_regexp = Util_Environment::home_domain_root_url_regexp();
120
 
121
  $buffer = preg_replace_callback(
214
 
215
  $test_url = Util_Environment::remove_query( $url );
216
  foreach ( $exceptions as $exception ) {
217
+ $escaped = str_replace( '~', '\~', $exception );
218
+ if ( trim( $exception ) && preg_match( '~' . $escaped . '~', $test_url ) )
219
  return false;
220
  }
221
 
Cache.php CHANGED
@@ -49,9 +49,9 @@ class Cache {
49
  case 'memcached':
50
  if ( class_exists( '\Memcached' ) ) {
51
  $instances[$instance_key] = new Cache_Memcached( $config );
52
- } else if ( class_exists( '\Memcache' ) ) {
53
- $instances[$instance_key] = new Cache_Memcache( $config );
54
- }
55
  break;
56
 
57
  case 'redis':
49
  case 'memcached':
50
  if ( class_exists( '\Memcached' ) ) {
51
  $instances[$instance_key] = new Cache_Memcached( $config );
52
+ } elseif ( class_exists( '\Memcache' ) ) {
53
+ $instances[$instance_key] = new Cache_Memcache( $config );
54
+ }
55
  break;
56
 
57
  case 'redis':
Cache_File_Generic.php CHANGED
@@ -50,7 +50,7 @@ class Cache_File_Generic extends Cache_File {
50
  $dir = dirname( $path );
51
 
52
  if ( !@is_dir( $dir ) ) {
53
- if ( !Util_File::mkdir_from( $dir, W3TC_CACHE_DIR ) )
54
  return false;
55
  }
56
 
@@ -128,7 +128,8 @@ class Cache_File_Generic extends Cache_File {
128
 
129
  }
130
 
131
- @touch( $path_old );
 
132
  }
133
  }
134
  $has_old_data = $exists;
@@ -186,16 +187,15 @@ class Cache_File_Generic extends Cache_File {
186
  return true;
187
 
188
  $old_entry_path = $path . '.old';
189
- if ( @rename( $path, $old_entry_path ) )
190
- return true;
191
-
192
- // if we can delete old entry - do second attempt to store in old-entry file
193
- if ( @unlink( $old_entry_path ) ) {
194
- if ( @rename( $path, $old_entry_path ) )
195
- return true;
196
  }
197
 
198
- return @unlink( $path );
 
199
  }
200
 
201
  /**
@@ -274,7 +274,7 @@ class Cache_File_Generic extends Cache_File {
274
  if ( $entry == '.' || $entry == '..' ) {
275
  continue;
276
  }
277
- if ( preg_match( '/' . $regex . '/', basename( $entry ) ) ) {
278
  Util_File::rmdir( $flush_dir . DIRECTORY_SEPARATOR . $entry );
279
  }
280
  }
50
  $dir = dirname( $path );
51
 
52
  if ( !@is_dir( $dir ) ) {
53
+ if ( !Util_File::mkdir_from_safe( $dir, W3TC_CACHE_DIR ) )
54
  return false;
55
  }
56
 
128
 
129
  }
130
 
131
+ // use old enough time to cause recalculation on next call
132
+ @touch( $path_old, 1479904835 );
133
  }
134
  }
135
  $has_old_data = $exists;
187
  return true;
188
 
189
  $old_entry_path = $path . '.old';
190
+ if ( ! @rename( $path, $old_entry_path ) ) {
191
+ // if we can delete old entry - do second attempt to store in old-entry file
192
+ if ( ! @unlink( $old_entry_path ) || ! @rename( $path, $old_entry_path ) ) {
193
+ return @unlink( $path );
194
+ }
 
 
195
  }
196
 
197
+ @touch( $old_entry_path, 1479904835 );
198
+ return true;
199
  }
200
 
201
  /**
274
  if ( $entry == '.' || $entry == '..' ) {
275
  continue;
276
  }
277
+ if ( preg_match( '~' . $regex . '~', basename( $entry ) ) ) {
278
  Util_File::rmdir( $flush_dir . DIRECTORY_SEPARATOR . $entry );
279
  }
280
  }
Cache_Memcache.php CHANGED
@@ -312,4 +312,10 @@ class Cache_Memcache extends Cache_Base {
312
 
313
  return $v;
314
  }
 
 
 
 
 
 
315
  }
312
 
313
  return $v;
314
  }
315
+
316
+ public function get_item_key( $name ) {
317
+ // memcached doesn't survive spaces in a key
318
+ $key = sprintf( 'w3tc_%s_%d_%s_%s', $this->_host, $this->_blog_id, $this->_module, md5( $name ) );
319
+ return $key;
320
+ }
321
  }
Cache_Memcached.php CHANGED
@@ -384,4 +384,10 @@ class Cache_Memcached extends Cache_Base {
384
 
385
  return $v;
386
  }
 
 
 
 
 
 
387
  }
384
 
385
  return $v;
386
  }
387
+
388
+ public function get_item_key( $name ) {
389
+ // memcached doesn't survive spaces in a key
390
+ $key = sprintf( 'w3tc_%s_%d_%s_%s', $this->_host, $this->_blog_id, $this->_module, md5( $name ) );
391
+ return $key;
392
+ }
393
  }
CdnEngine_Azure.php CHANGED
@@ -26,6 +26,9 @@ class CdnEngine_Azure extends CdnEngine_Base {
26
  ), $config );
27
 
28
  parent::__construct( $config );
 
 
 
29
  }
30
 
31
  /**
@@ -37,7 +40,6 @@ class CdnEngine_Azure extends CdnEngine_Base {
37
  function _init( &$error ) {
38
  if ( empty( $this->_config['user'] ) ) {
39
  $error = 'Empty account name.';
40
-
41
  return false;
42
  }
43
 
@@ -53,17 +55,18 @@ class CdnEngine_Azure extends CdnEngine_Base {
53
  return false;
54
  }
55
 
56
- set_include_path( get_include_path() . PATH_SEPARATOR . W3TC_LIB_DIR );
57
-
58
- require_once 'Microsoft/WindowsAzure/Storage/Blob.php';
59
-
60
- $this->_client = new \Microsoft_WindowsAzure_Storage_Blob(
61
- \Microsoft_WindowsAzure_Storage::URL_CLOUD_BLOB,
62
- $this->_config['user'],
63
- $this->_config['key'],
64
- false,
65
- \Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract::noRetry()
66
- );
 
67
 
68
  return true;
69
  }
@@ -93,12 +96,6 @@ class CdnEngine_Azure extends CdnEngine_Base {
93
  $remote_path = $file['remote_path'];
94
 
95
  $results[] = $this->_upload( $file, $force_rewrite );
96
-
97
- if ( $this->_config['compression'] && $this->_may_gzip( $remote_path ) ) {
98
- $file['remote_path_gzip'] = $remote_path . $this->_gzip_extension;
99
-
100
- $results[] = $this->_upload_gzip( $file, $force_rewrite );
101
- }
102
  }
103
 
104
  return !$this->_is_error( $results );
@@ -121,15 +118,18 @@ class CdnEngine_Azure extends CdnEngine_Base {
121
  W3TC_CDN_RESULT_ERROR, 'Source file not found.', $file );
122
  }
123
 
124
- $md5 = @md5_file( $local_path );
 
125
  $content_md5 = $this->_get_content_md5( $md5 );
126
 
127
  if ( !$force_rewrite ) {
128
  try {
129
- $properties = $this->_client->getBlobProperties( $this->_config['container'], $remote_path );
130
- $size = @filesize( $local_path );
 
 
131
 
132
- if ( $size === (int) $properties->Size && $content_md5 === $properties->ContentMd5 ) {
133
  return $this->_get_result( $local_path, $remote_path,
134
  W3TC_CDN_RESULT_OK, 'File up-to-date.', $file );
135
  }
@@ -143,7 +143,8 @@ class CdnEngine_Azure extends CdnEngine_Base {
143
  ) );
144
 
145
  try {
146
- $this->_client->putBlob( $this->_config['container'], $remote_path, $local_path, array(), null, $headers );
 
147
  } catch ( \Exception $exception ) {
148
  return $this->_get_result( $local_path, $remote_path,
149
  W3TC_CDN_RESULT_ERROR,
@@ -155,70 +156,6 @@ class CdnEngine_Azure extends CdnEngine_Base {
155
  'OK', $file );
156
  }
157
 
158
- /**
159
- * Uploads gzipped file
160
- *
161
- * @param array $file CDN file array
162
- * @param bool $force_rewrite
163
- * @return array
164
- */
165
- function _upload_gzip( $file, $force_rewrite = false ) {
166
- $local_path = $file['local_path'];
167
- $remote_path = $file['remote_path_gzip'];
168
-
169
- if ( !function_exists( 'gzencode' ) ) {
170
- return $this->_get_result( $local_path, $remote_path,
171
- W3TC_CDN_RESULT_ERROR, "GZIP library doesn't exists.", $file );
172
- }
173
-
174
- if ( !file_exists( $local_path ) ) {
175
- return $this->_get_result( $local_path, $remote_path,
176
- W3TC_CDN_RESULT_ERROR, 'Source file not found.', $file );
177
- }
178
-
179
- $contents = @file_get_contents( $local_path );
180
-
181
- if ( $contents === false ) {
182
- return $this->_get_result( $local_path, $remote_path,
183
- W3TC_CDN_RESULT_ERROR, 'Unable to read file.', $file );
184
- }
185
-
186
- $data = gzencode( $contents );
187
- $md5 = md5( $data );
188
- $content_md5 = $this->_get_content_md5( $md5 );
189
-
190
- if ( !$force_rewrite ) {
191
- try {
192
- $properties = $this->_client->getBlobProperties( $this->_config['container'], $remote_path );
193
- $size = @filesize( $local_path );
194
-
195
- if ( $size === (int) $properties->Size && $content_md5 === $properties->ContentMd5 ) {
196
- return $this->_get_result( $local_path, $remote_path,
197
- W3TC_CDN_RESULT_OK, 'File up-to-date.', $file );
198
- }
199
- } catch ( \Exception $exception ) {
200
- }
201
- }
202
-
203
- $headers = $this->_get_headers( $file );
204
- $headers = array_merge( $headers, array(
205
- 'Content-MD5' => $content_md5,
206
- 'Content-Encoding' => 'gzip'
207
- ) );
208
-
209
- try {
210
- $this->_client->putBlobData( $this->_config['container'], $remote_path, $data, array(), null, $headers );
211
- } catch ( \Exception $exception ) {
212
- return $this->_get_result( $local_path, $remote_path,
213
- W3TC_CDN_RESULT_ERROR,
214
- sprintf( 'Unable to put blob (%s).', $exception->getMessage() ),
215
- $file );
216
- }
217
-
218
- return $this->_get_result( $local_path, $remote_path,
219
- W3TC_CDN_RESULT_OK, 'OK', $file );
220
- }
221
-
222
  /**
223
  * Deletes files from storage
224
  *
@@ -249,23 +186,6 @@ class CdnEngine_Azure extends CdnEngine_Base {
249
  sprintf( 'Unable to delete blob (%s).', $exception->getMessage() ),
250
  $file );
251
  }
252
-
253
- if ( $this->_config['compression'] ) {
254
- $remote_path_gzip = $remote_path . $this->_gzip_extension;
255
-
256
- try {
257
- $this->_client->deleteBlob( $this->_config['container'], $remote_path_gzip );
258
- $results[] = $this->_get_result( $local_path,
259
- $remote_path_gzip, W3TC_CDN_RESULT_OK, 'OK',
260
- $file );
261
- } catch ( \Exception $exception ) {
262
- $results[] = $this->_get_result( $local_path,
263
- $remote_path_gzip, W3TC_CDN_RESULT_ERROR,
264
- sprintf( 'Unable to delete blob (%s).',
265
- $exception->getMessage() ),
266
- $file );
267
- }
268
- }
269
  }
270
 
271
  return !$this->_is_error( $results );
@@ -298,8 +218,8 @@ class CdnEngine_Azure extends CdnEngine_Base {
298
 
299
  $container = null;
300
 
301
- foreach ( (array) $containers as $_container ) {
302
- if ( $_container->Name == $this->_config['container'] ) {
303
  $container = $_container;
304
  break;
305
  }
@@ -312,21 +232,42 @@ class CdnEngine_Azure extends CdnEngine_Base {
312
  }
313
 
314
  try {
315
- $this->_client->putBlobData( $this->_config['container'], $string, $string );
316
  } catch ( \Exception $exception ) {
317
- $error = sprintf( 'Unable to put blob data (%s).', $exception->getMessage() );
 
 
318
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
  return false;
320
  }
321
 
322
  try {
323
- $data = $this->_client->getBlobData( $this->_config['container'], $string );
 
 
324
  } catch ( \Exception $exception ) {
325
  $error = sprintf( 'Unable to get blob data (%s).', $exception->getMessage() );
326
-
327
  return false;
328
  }
329
 
 
330
  if ( $data != $string ) {
331
  try {
332
  $this->_client->deleteBlob( $this->_config['container'], $string );
@@ -334,7 +275,6 @@ class CdnEngine_Azure extends CdnEngine_Base {
334
  }
335
 
336
  $error = 'Blob datas are not equal.';
337
-
338
  return false;
339
  }
340
 
@@ -404,8 +344,11 @@ class CdnEngine_Azure extends CdnEngine_Base {
404
  }
405
 
406
  try {
407
- $this->_client->createContainer( $this->_config['container'] );
408
- $this->_client->setContainerAcl( $this->_config['container'], \Microsoft_WindowsAzure_Storage_Blob::ACL_PUBLIC_BLOB );
 
 
 
409
  } catch ( \Exception $exception ) {
410
  $error = sprintf( 'Unable to create container: %s (%s)', $this->_config['container'], $exception->getMessage() );
411
 
@@ -450,7 +393,7 @@ class CdnEngine_Azure extends CdnEngine_Base {
450
  * @param array $file CDN file array
451
  * @return array
452
  */
453
- function _get_headers( $file ) {
454
  $allowed_headers = array(
455
  'Content-Length',
456
  'Content-Type',
26
  ), $config );
27
 
28
  parent::__construct( $config );
29
+
30
+ require_once W3TC_LIB_DIR . DIRECTORY_SEPARATOR . 'Azure' .
31
+ DIRECTORY_SEPARATOR . 'loader.php';
32
  }
33
 
34
  /**
40
  function _init( &$error ) {
41
  if ( empty( $this->_config['user'] ) ) {
42
  $error = 'Empty account name.';
 
43
  return false;
44
  }
45
 
55
  return false;
56
  }
57
 
58
+ try {
59
+ $connectionString = 'DefaultEndpointsProtocol=https;AccountName=' .
60
+ $this->_config['user'] .
61
+ ';AccountKey=' . $this->_config['key'];
62
+
63
+ $this->_client = \MicrosoftAzure\Storage\Common\ServicesBuilder::getInstance()->createBlobService(
64
+ $connectionString);
65
+ } catch ( \Exception $ex ) {
66
+ $error = $ex->getMessage();
67
+ return false;
68
+ }
69
+
70
 
71
  return true;
72
  }
96
  $remote_path = $file['remote_path'];
97
 
98
  $results[] = $this->_upload( $file, $force_rewrite );
 
 
 
 
 
 
99
  }
100
 
101
  return !$this->_is_error( $results );
118
  W3TC_CDN_RESULT_ERROR, 'Source file not found.', $file );
119
  }
120
 
121
+ $contents = @file_get_contents( $local_path );
122
+ $md5 = md5( $contents ); // @md5_file( $local_path );
123
  $content_md5 = $this->_get_content_md5( $md5 );
124
 
125
  if ( !$force_rewrite ) {
126
  try {
127
+ $propertiesResult = $this->_client->getBlobProperties( $this->_config['container'], $remote_path );
128
+ $p = $propertiesResult->getProperties();
129
+
130
+ $local_size = @filesize( $local_path );
131
 
132
+ if ( $local_size == $p->getContentLength() && $content_md5 === $p->getContentMD5() ) {
133
  return $this->_get_result( $local_path, $remote_path,
134
  W3TC_CDN_RESULT_OK, 'File up-to-date.', $file );
135
  }
143
  ) );
144
 
145
  try {
146
+ // $headers
147
+ $this->_client->createBlockBlob( $this->_config['container'], $remote_path, $contents );
148
  } catch ( \Exception $exception ) {
149
  return $this->_get_result( $local_path, $remote_path,
150
  W3TC_CDN_RESULT_ERROR,
156
  'OK', $file );
157
  }
158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  /**
160
  * Deletes files from storage
161
  *
186
  sprintf( 'Unable to delete blob (%s).', $exception->getMessage() ),
187
  $file );
188
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  }
190
 
191
  return !$this->_is_error( $results );
218
 
219
  $container = null;
220
 
221
+ foreach ( $containers->getContainers() as $_container ) {
222
+ if ( $_container->getName() == $this->_config['container'] ) {
223
  $container = $_container;
224
  break;
225
  }
232
  }
233
 
234
  try {
235
+ $this->_client->createBlockBlob( $this->_config['container'], $string, $string );
236
  } catch ( \Exception $exception ) {
237
+ $error = sprintf( 'Unable to create blob (%s).', $exception->getMessage() );
238
+ return false;
239
+ }
240
 
241
+ try {
242
+ $propertiesResult = $this->_client->getBlobProperties( $this->_config['container'], $string );
243
+ $p = $propertiesResult->getProperties();
244
+ $size = $p->getContentLength();
245
+ $md5 = $p->getContentMD5();
246
+ } catch ( \Exception $exception ) {
247
+ $error = sprintf( 'Unable to get blob properties (%s).', $exception->getMessage() );
248
+ return false;
249
+ }
250
+
251
+ if ( $size != strlen( $string ) || $this->_get_content_md5( md5( $string ) ) != $md5 ) {
252
+ try {
253
+ $this->_client->deleteBlob( $this->_config['container'], $string );
254
+ } catch ( \Exception $exception ) {
255
+ }
256
+
257
+ $error = 'Blob data properties are not equal.';
258
  return false;
259
  }
260
 
261
  try {
262
+ $getBlob = $this->_client->getBlob( $this->_config['container'], $string );
263
+ $dataStream = $getBlob->getContentStream();
264
+ $data = stream_get_contents( $dataStream );
265
  } catch ( \Exception $exception ) {
266
  $error = sprintf( 'Unable to get blob data (%s).', $exception->getMessage() );
 
267
  return false;
268
  }
269
 
270
+
271
  if ( $data != $string ) {
272
  try {
273
  $this->_client->deleteBlob( $this->_config['container'], $string );
275
  }
276
 
277
  $error = 'Blob datas are not equal.';
 
278
  return false;
279
  }
280
 
344
  }
345
 
346
  try {
347
+ $createContainerOptions = new \MicrosoftAzure\Storage\Blob\Models\CreateContainerOptions();
348
+ $createContainerOptions->setPublicAccess(
349
+ \MicrosoftAzure\Storage\Blob\Models\PublicAccessType::CONTAINER_AND_BLOBS );
350
+
351
+ $this->_client->createContainer( $this->_config['container'], $createContainerOptions );
352
  } catch ( \Exception $exception ) {
353
  $error = sprintf( 'Unable to create container: %s (%s)', $this->_config['container'], $exception->getMessage() );
354
 
393
  * @param array $file CDN file array
394
  * @return array
395
  */
396
+ function _get_headers( $file, $block_expires = false ) {
397
  $allowed_headers = array(
398
  'Content-Length',
399
  'Content-Type',
CdnEngine_GoogleDrive.php CHANGED
@@ -30,12 +30,17 @@ class CdnEngine_GoogleDrive extends CdnEngine_Base {
30
 
31
  try {
32
  $this->_init_service( $config['access_token'] );
33
- } catch ( \Exception $e ) {}
 
 
34
  }
35
 
36
 
37
 
38
  private function _init_service( $access_token ) {
 
 
 
39
  $client = new \W3TCG_Google_Client();
40
  $client->setClientId( $this->_client_id );
41
  $client->setAccessToken( $access_token );
@@ -72,6 +77,9 @@ class CdnEngine_GoogleDrive extends CdnEngine_Base {
72
  * @return boolean
73
  */
74
  function upload( $files, &$results, $force_rewrite = false, $timeout_time = NULL ) {
 
 
 
75
  $allow_refresh_token = true;
76
  $result = true;
77
 
30
 
31
  try {
32
  $this->_init_service( $config['access_token'] );
33
+ } catch ( \Exception $e ) {
34
+ $this->_service = null;
35
+ }
36
  }
37
 
38
 
39
 
40
  private function _init_service( $access_token ) {
41
+ if ( empty( $this->_client_id ) || empty( $access_token ) )
42
+ throw new \Exception('service not configured');
43
+
44
  $client = new \W3TCG_Google_Client();
45
  $client->setClientId( $this->_client_id );
46
  $client->setAccessToken( $access_token );
77
  * @return boolean
78
  */
79
  function upload( $files, &$results, $force_rewrite = false, $timeout_time = NULL ) {
80
+ if ( is_null( $this->_service ) )
81
+ return false;
82
+
83
  $allow_refresh_token = true;
84
  $result = true;
85
 
Cdn_Core.php CHANGED
@@ -358,7 +358,7 @@ class Cdn_Core {
358
  'container' => $this->_config->get_string( 'cdn.azure.container' ),
359
  'cname' => $this->_config->get_array( 'cdn.azure.cname' ),
360
  'ssl' => $this->_config->get_string( 'cdn.azure.ssl' ),
361
- 'compression' => $compression
362
  );
363
  break;
364
 
358
  'container' => $this->_config->get_string( 'cdn.azure.container' ),
359
  'cname' => $this->_config->get_array( 'cdn.azure.cname' ),
360
  'ssl' => $this->_config->get_string( 'cdn.azure.ssl' ),
361
+ 'compression' => false
362
  );
363
  break;
364
 
Cdn_Plugin.php CHANGED
@@ -293,7 +293,7 @@ class Cdn_Plugin {
293
  * @return string
294
  */
295
  function ob_callback( $buffer ) {
296
- if ( $buffer != '' && Util_Content::is_html( $buffer ) ) {
297
  if ( $this->can_cdn2( $buffer ) ) {
298
  $srcset_helper = new _Cdn_Plugin_ContentFilter();
299
  $buffer = $srcset_helper->replace_all_links( $buffer );
@@ -613,6 +613,8 @@ class Cdn_Plugin {
613
 
614
  foreach ( $reject_uri as $expr ) {
615
  $expr = trim( $expr );
 
 
616
  if ( $expr != '' && preg_match( '~' . $expr . '~i', $_SERVER['REQUEST_URI'] ) ) {
617
  return false;
618
  }
@@ -630,7 +632,7 @@ class Cdn_Plugin {
630
  * @return boolean
631
  */
632
  private function _check_logged_in_role_allowed() {
633
- global $current_user;
634
 
635
  if ( !is_user_logged_in() )
636
  return true;
@@ -994,27 +996,49 @@ class _Cdn_Plugin_ContentFilter {
994
 
995
  if ( $this->_config->get_boolean( 'cdn.custom.enable' ) ) {
996
  $masks = $this->_config->get_array( 'cdn.custom.files' );
997
- $masks = array_map( array( '\W3TC\Cdn_Util', 'replace_folder_placeholders' ), $masks );
998
  $masks = array_map( array( '\W3TC\Util_Environment', 'parse_path' ), $masks );
999
 
1000
  if ( count( $masks ) ) {
1001
- $mask_regexps = array();
 
 
1002
 
1003
  foreach ( $masks as $mask ) {
1004
- if ( $mask != '' ) {
1005
- $mask = Util_Environment::normalize_file( $mask );
1006
- $mask_regexps[] = Cdn_Util::get_regexp_by_mask( $mask );
 
 
 
 
 
 
 
 
 
1007
  }
1008
  }
1009
 
1010
- $regexps[] = '~(["\'(=])\s*((' . $domain_url_regexp .
1011
- ')?(' . Util_Environment::preg_quote( $site_path ) .
1012
- '(' . implode( '|', $mask_regexps ) . ')([^"\'() >]*)))~i';
1013
- if ( $site_domain_url_regexp )
1014
- $regexps[] = '~(["\'(=])\s*((' .
1015
- $site_domain_url_regexp . ')?(' .
1016
- Util_Environment::preg_quote( $site_path ) . '(' .
1017
- implode( '|', $mask_regexps ) . ')([^"\'() >]*)))~i';
 
 
 
 
 
 
 
 
 
 
 
1018
  }
1019
  }
1020
 
293
  * @return string
294
  */
295
  function ob_callback( $buffer ) {
296
+ if ( $buffer != '' && Util_Content::is_html_xml( $buffer ) ) {
297
  if ( $this->can_cdn2( $buffer ) ) {
298
  $srcset_helper = new _Cdn_Plugin_ContentFilter();
299
  $buffer = $srcset_helper->replace_all_links( $buffer );
613
 
614
  foreach ( $reject_uri as $expr ) {
615
  $expr = trim( $expr );
616
+ $expr = str_replace( '~', '\~', $expr );
617
+
618
  if ( $expr != '' && preg_match( '~' . $expr . '~i', $_SERVER['REQUEST_URI'] ) ) {
619
  return false;
620
  }
632
  * @return boolean
633
  */
634
  private function _check_logged_in_role_allowed() {
635
+ $current_user = wp_get_current_user();
636
 
637
  if ( !is_user_logged_in() )
638
  return true;
996
 
997
  if ( $this->_config->get_boolean( 'cdn.custom.enable' ) ) {
998
  $masks = $this->_config->get_array( 'cdn.custom.files' );
999
+ $masks = array_map( array( '\W3TC\Cdn_Util', 'replace_folder_placeholders_to_uri' ), $masks );
1000
  $masks = array_map( array( '\W3TC\Util_Environment', 'parse_path' ), $masks );
1001
 
1002
  if ( count( $masks ) ) {
1003
+ $custom_regexps_urls = array();
1004
+ $custom_regexps_uris = array();
1005
+ $custom_regexps_docroot_related = array();
1006
 
1007
  foreach ( $masks as $mask ) {
1008
+ if ( !empty( $mask ) ) {
1009
+ if ( Util_Environment::is_url( $mask ) ) {
1010
+ $custom_regexps_urls[] = Cdn_Util::get_regexp_by_mask( $mask );
1011
+ } elseif ( substr( $mask, 0, 1 ) == '/' ) { // uri
1012
+ $custom_regexps_uris[] = Cdn_Util::get_regexp_by_mask( $mask );
1013
+ } else {
1014
+ $file = Util_Environment::normalize_path( $mask ); // \ -> backspaces
1015
+ $file = str_replace( Util_Environment::site_root(), '', $file );
1016
+ $file = ltrim( $file, '/' );
1017
+
1018
+ $custom_regexps_docroot_related[] = Cdn_Util::get_regexp_by_mask( $mask );
1019
+ }
1020
  }
1021
  }
1022
 
1023
+ if ( count( $custom_regexps_urls ) > 0 ) {
1024
+ foreach ( $custom_regexps_urls as $regexp )
1025
+ $regexps[] = '~(["\'(=])\s*((' . $regexp . ')?(()([^"\'() >]*)))~i';
1026
+ }
1027
+ if ( count( $custom_regexps_uris ) > 0 ) {
1028
+ $regexps[] = '~(["\'(=])\s*((' . $domain_url_regexp .
1029
+ ')?((' . implode( '|', $custom_regexps_uris ) . ')([^"\'() >]*)))~i';
1030
+ }
1031
+
1032
+ if ( count( $custom_regexps_docroot_related ) > 0) {
1033
+ $regexps[] = '~(["\'(=])\s*((' . $domain_url_regexp .
1034
+ ')?(' . Util_Environment::preg_quote( $site_path ) .
1035
+ '(' . implode( '|', $custom_regexps_docroot_related ) . ')([^"\'() >]*)))~i';
1036
+ if ( $site_domain_url_regexp )
1037
+ $regexps[] = '~(["\'(=])\s*((' .
1038
+ $site_domain_url_regexp . ')?(' .
1039
+ Util_Environment::preg_quote( $site_path ) . '(' .
1040
+ implode( '|', $custom_regexps_docroot_related ) . ')([^"\'() >]*)))~i';
1041
+ }
1042
  }
1043
  }
1044
 
Cdn_RackSpace_Api_CaCert.pem → Cdn_RackSpace_Api_CaCert-example.pem RENAMED
File without changes
Cdn_RackSpace_Api_Cdn.php CHANGED
@@ -81,8 +81,8 @@ class Cdn_RackSpace_Api_Cdn {
81
  $url_base = $this->_access_region_descriptor['cdn.publicURL'];
82
 
83
  $result = wp_remote_get( $url_base . $uri . '?format=json', array(
84
- 'headers' => 'X-Auth-Token: ' . $this->_access_token,
85
- 'sslcertificates' => dirname( __FILE__ ) . '/Cdn_RackSpace_Api_CaCert.pem'
86
  ) );
87
 
88
  $r = self::_decode_response_json( $result );
@@ -104,7 +104,7 @@ class Cdn_RackSpace_Api_Cdn {
104
  $result = wp_remote_post( $url_base . $uri, array(
105
  'headers' => $headers,
106
  'body' => $body,
107
- 'sslcertificates' => dirname( __FILE__ ) . '/Cdn_RackSpace_Api_CaCert.pem',
108
  'method' => 'PATCH'
109
  ) );
110
 
@@ -129,8 +129,8 @@ class Cdn_RackSpace_Api_Cdn {
129
 
130
  $result = wp_remote_post( $url_base . $uri, array(
131
  'headers' => $headers,
132
- 'body' => $body,
133
- 'sslcertificates' => dirname( __FILE__ ) . '/Cdn_RackSpace_Api_CaCert.pem'
134
  ) );
135
 
136
  $r = self::_decode_response( $result );
@@ -154,7 +154,7 @@ class Cdn_RackSpace_Api_Cdn {
154
 
155
  $result = wp_remote_post( $url_base . $uri, array(
156
  'headers' => $headers,
157
- 'sslcertificates' => dirname( __FILE__ ) . '/Cdn_RackSpace_Api_CaCert.pem',
158
  'method' => 'DELETE'
159
  ) );
160
 
@@ -164,7 +164,7 @@ class Cdn_RackSpace_Api_Cdn {
164
  }
165
 
166
  $new_object = call_user_func( $this->_new_access_required );
167
- return $new_object->_wp_remote_delete( $uri, $body );
168
  }
169
 
170
 
@@ -176,6 +176,12 @@ class Cdn_RackSpace_Api_Cdn {
176
  if ( empty( $result['body'] ) )
177
  $response_json = array();
178
  else {
 
 
 
 
 
 
179
  $response_json = @json_decode( $result['body'], true );
180
  if ( is_null( $response_json ) )
181
  throw new \Exception(
@@ -189,7 +195,10 @@ class Cdn_RackSpace_Api_Cdn {
189
  $result['response']['code'] != '204' )
190
  throw new \Exception( $result['body'] );
191
 
192
- return array( 'response_json' => $response_json, 'auth_required' => false );
 
 
 
193
  }
194
 
195
 
@@ -202,6 +211,13 @@ class Cdn_RackSpace_Api_Cdn {
202
  $result['response']['code'] != '201' &&
203
  $result['response']['code'] != '202' &&
204
  $result['response']['code'] != '204' ) {
 
 
 
 
 
 
 
205
  // try to decode response
206
  $response_json = @json_decode( $result['body'], true );
207
  if ( is_null( $response_json ) ||
81
  $url_base = $this->_access_region_descriptor['cdn.publicURL'];
82
 
83
  $result = wp_remote_get( $url_base . $uri . '?format=json', array(
84
+ 'headers' => 'X-Auth-Token: ' . $this->_access_token
85
+ //'sslcertificates' => dirname( __FILE__ ) . '/Cdn_RackSpace_Api_CaCert.pem'
86
  ) );
87
 
88
  $r = self::_decode_response_json( $result );
104
  $result = wp_remote_post( $url_base . $uri, array(
105
  'headers' => $headers,
106
  'body' => $body,
107
+ //'sslcertificates' => dirname( __FILE__ ) . '/Cdn_RackSpace_Api_CaCert.pem',
108
  'method' => 'PATCH'
109
  ) );
110
 
129
 
130
  $result = wp_remote_post( $url_base . $uri, array(
131
  'headers' => $headers,
132
+ 'body' => $body
133
+ //'sslcertificates' => dirname( __FILE__ ) . '/Cdn_RackSpace_Api_CaCert.pem'
134
  ) );
135
 
136
  $r = self::_decode_response( $result );
154
 
155
  $result = wp_remote_post( $url_base . $uri, array(
156
  'headers' => $headers,
157
+ //'sslcertificates' => dirname( __FILE__ ) . '/Cdn_RackSpace_Api_CaCert.pem',
158
  'method' => 'DELETE'
159
  ) );
160
 
164
  }
165
 
166
  $new_object = call_user_func( $this->_new_access_required );
167
+ return $new_object->_wp_remote_delete( $uri, array() );
168
  }
169
 
170
 
176
  if ( empty( $result['body'] ) )
177
  $response_json = array();
178
  else {
179
+ if ( $result['body'] == 'Unauthorized' )
180
+ return array(
181
+ 'response_json' => array(),
182
+ 'auth_required' => true
183
+ );
184
+
185
  $response_json = @json_decode( $result['body'], true );
186
  if ( is_null( $response_json ) )
187
  throw new \Exception(
195
  $result['response']['code'] != '204' )
196
  throw new \Exception( $result['body'] );
197
 
198
+ return array(
199
+ 'response_json' => $response_json,
200
+ 'auth_required' => false
201
+ );
202
  }
203
 
204
 
211
  $result['response']['code'] != '201' &&
212
  $result['response']['code'] != '202' &&
213
  $result['response']['code'] != '204' ) {
214
+
215
+ if ( $result['response']['message'] == 'Unauthorized' )
216
+ return array(
217
+ 'response_json' => array(),
218
+ 'auth_required' => true
219
+ );
220
+
221
  // try to decode response
222
  $response_json = @json_decode( $result['body'], true );
223
  if ( is_null( $response_json ) ||
Cdn_RackSpace_Api_CloudFiles.php CHANGED
@@ -69,8 +69,8 @@ class Cdn_RackSpace_Api_CloudFiles {
69
  $result = wp_remote_post( $url_base . $uri . '?format=json', array(
70
  'headers' => $headers,
71
  'body' => $body,
72
- 'sslcertificates' => dirname( __FILE__ ) .
73
- '/Cdn_RackSpace_Api_CaCert.pem',
74
  'timeout' => 120,
75
  'method' => 'PUT'
76
  ) );
@@ -92,8 +92,8 @@ class Cdn_RackSpace_Api_CloudFiles {
92
 
93
  $result = wp_remote_get( $url_base . $uri . '?format=json', array(
94
  'headers' => array( 'X-Auth-Token' => $this->_access_token ),
95
- 'sslcertificates' => dirname( __FILE__ ) .
96
- '/Cdn_RackSpace_Api_CaCert.pem',
97
  'method' => 'HEAD'
98
  ) );
99
 
@@ -117,8 +117,8 @@ class Cdn_RackSpace_Api_CloudFiles {
117
 
118
  $result = wp_remote_post( $url_base . $uri . '?format=json', array(
119
  'headers' => array( 'X-Auth-Token' => $this->_access_token ),
120
- 'sslcertificates' => dirname( __FILE__ ) .
121
- '/Cdn_RackSpace_Api_CaCert.pem',
122
  'method' => 'DELETE'
123
  ) );
124
 
@@ -140,10 +140,17 @@ class Cdn_RackSpace_Api_CloudFiles {
140
  if ( $result['response']['code'] != '200' &&
141
  $result['response']['code'] != '201' &&
142
  $result['response']['code'] != '202' &&
143
- $result['response']['code'] != '204' )
 
 
 
 
 
 
144
  throw new \Exception(
145
  'Failed to reach API endpoint, got unexpected response ' .
146
  $result['response']['message'] );
 
147
 
148
  return array( 'auth_required' => false );
149
  }
69
  $result = wp_remote_post( $url_base . $uri . '?format=json', array(
70
  'headers' => $headers,
71
  'body' => $body,
72
+ //'sslcertificates' => dirname( __FILE__ ) .
73
+ //'/Cdn_RackSpace_Api_CaCert.pem',
74
  'timeout' => 120,
75
  'method' => 'PUT'
76
  ) );
92
 
93
  $result = wp_remote_get( $url_base . $uri . '?format=json', array(
94
  'headers' => array( 'X-Auth-Token' => $this->_access_token ),
95
+ //'sslcertificates' => dirname( __FILE__ ) .
96
+ //'/Cdn_RackSpace_Api_CaCert.pem',
97
  'method' => 'HEAD'
98
  ) );
99
 
117
 
118
  $result = wp_remote_post( $url_base . $uri . '?format=json', array(
119
  'headers' => array( 'X-Auth-Token' => $this->_access_token ),
120
+ //'sslcertificates' => dirname( __FILE__ ) .
121
+ //'/Cdn_RackSpace_Api_CaCert.pem',
122
  'method' => 'DELETE'
123
  ) );
124
 
140
  if ( $result['response']['code'] != '200' &&
141
  $result['response']['code'] != '201' &&
142
  $result['response']['code'] != '202' &&
143
+ $result['response']['code'] != '204' ) {
144
+
145
+ if ( $result['response']['message'] == 'Unauthorized' )
146
+ return array(
147
+ 'auth_required' => true
148
+ );
149
+
150
  throw new \Exception(
151
  'Failed to reach API endpoint, got unexpected response ' .
152
  $result['response']['message'] );
153
+ }
154
 
155
  return array( 'auth_required' => false );
156
  }
Cdn_RackSpace_Api_CloudFilesCdn.php CHANGED
@@ -42,8 +42,8 @@ class Cdn_RackSpace_Api_CloudFilesCdn {
42
  $url_base = $this->_access_region_descriptor['object-cdn.publicURL'];
43
 
44
  $result = wp_remote_get( $url_base . $uri . '?format=json', array(
45
- 'headers' => 'X-Auth-Token: ' . $this->_access_token,
46
- 'sslcertificates' => dirname( __FILE__ ) . '/Cdn_RackSpace_Api_CaCert.pem'
47
  ) );
48
 
49
  $r = self::_decode_response_json( $result );
@@ -63,7 +63,7 @@ class Cdn_RackSpace_Api_CloudFilesCdn {
63
 
64
  $result = wp_remote_get( $url_base . $uri . '?format=json', array(
65
  'headers' => 'X-Auth-Token: ' . $this->_access_token,
66
- 'sslcertificates' => dirname( __FILE__ ) . '/Cdn_RackSpace_Api_CaCert.pem',
67
  'method' => 'HEAD'
68
  ) );
69
 
@@ -86,7 +86,7 @@ class Cdn_RackSpace_Api_CloudFilesCdn {
86
  $result = wp_remote_post( $url_base . $uri, array(
87
  'headers' => $headers,
88
  'body' => $body,
89
- 'sslcertificates' => dirname( __FILE__ ) . '/Cdn_RackSpace_Api_CaCert.pem',
90
  'method' => 'PUT'
91
  ) );
92
 
@@ -133,10 +133,17 @@ class Cdn_RackSpace_Api_CloudFilesCdn {
133
  if ( $result['response']['code'] != '200' &&
134
  $result['response']['code'] != '201' &&
135
  $result['response']['code'] != '202' &&
136
- $result['response']['code'] != '204' )
 
 
 
 
 
 
137
  throw new \Exception(
138
  'Failed to reach API endpoint, got unexpected response ' .
139
  $result['response']['message'] );
 
140
 
141
  return array( 'auth_required' => false );
142
  }
42
  $url_base = $this->_access_region_descriptor['object-cdn.publicURL'];
43
 
44
  $result = wp_remote_get( $url_base . $uri . '?format=json', array(
45
+ 'headers' => 'X-Auth-Token: ' . $this->_access_token
46
+ //'sslcertificates' => dirname( __FILE__ ) . '/Cdn_RackSpace_Api_CaCert.pem'
47
  ) );
48
 
49
  $r = self::_decode_response_json( $result );
63
 
64
  $result = wp_remote_get( $url_base . $uri . '?format=json', array(
65
  'headers' => 'X-Auth-Token: ' . $this->_access_token,
66
+ //'sslcertificates' => dirname( __FILE__ ) . '/Cdn_RackSpace_Api_CaCert.pem',
67
  'method' => 'HEAD'
68
  ) );
69
 
86
  $result = wp_remote_post( $url_base . $uri, array(
87
  'headers' => $headers,
88
  'body' => $body,
89
+ //'sslcertificates' => dirname( __FILE__ ) . '/Cdn_RackSpace_Api_CaCert.pem',
90
  'method' => 'PUT'
91
  ) );
92
 
133
  if ( $result['response']['code'] != '200' &&
134
  $result['response']['code'] != '201' &&
135
  $result['response']['code'] != '202' &&
136
+ $result['response']['code'] != '204' ) {
137
+
138
+ if ( $result['response']['message'] == 'Unauthorized' )
139
+ return array(
140
+ 'auth_required' => true
141
+ );
142
+
143
  throw new \Exception(
144
  'Failed to reach API endpoint, got unexpected response ' .
145
  $result['response']['message'] );
146
+ }
147
 
148
  return array( 'auth_required' => false );
149
  }
Cdn_RackSpace_Api_Tokens.php CHANGED
@@ -18,8 +18,8 @@ class Cdn_RackSpace_Api_Tokens {
18
  'Accept' => 'application/json',
19
  'Content-Type' => 'application/json'
20
  ),
21
- 'sslcertificates' => dirname( __FILE__ ) .
22
- '/Cdn_RackSpace_Api_CaCert.pem',
23
  'body' => json_encode( $request_json )
24
  )
25
  );
18
  'Accept' => 'application/json',
19
  'Content-Type' => 'application/json'
20
  ),
21
+ //'sslcertificates' => dirname( __FILE__ ) .
22
+ //'/Cdn_RackSpace_Api_CaCert.pem',
23
  'body' => json_encode( $request_json )
24
  )
25
  );
Cdn_Util.php CHANGED
@@ -221,4 +221,23 @@ class Cdn_Util {
221
 
222
  return $file;
223
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  }
221
 
222
  return $file;
223
  }
224
+
225
+ static function replace_folder_placeholders_to_uri( $file ) {
226
+ static $content_uri, $plugins_uri, $uploads_uri;
227
+ if ( empty( $content_uri ) ) {
228
+ $content_uri = Util_Environment::url_to_uri( content_url() );
229
+ $plugins_uri = Util_Environment::url_to_uri( plugins_url() );
230
+
231
+ $upload_dir = Util_Environment::wp_upload_dir();
232
+ if ( isset( $upload_dir['baseurl'] ) )
233
+ $uploads_uri = $upload_dir['baseurl'];
234
+ else
235
+ $uploads_uri = '';
236
+ }
237
+ $file = str_replace( '{wp_content_dir}', $content_uri, $file );
238
+ $file = str_replace( '{plugins_dir}', $plugins_uri, $file );
239
+ $file = str_replace( '{uploads_dir}', $uploads_uri, $file );
240
+
241
+ return $file;
242
+ }
243
  }
Cli.php CHANGED
@@ -2,18 +2,71 @@
2
  namespace W3TC;
3
 
4
  /**
5
- * The W3 Total Cache plugin
6
  *
7
  * @package wp-cli
8
  * @subpackage commands/third-party
9
  */
10
  class W3TotalCache_Command extends \WP_CLI_Command {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
  /**
13
- * Clear something from the cache
14
  *
15
- * @param array $args
16
- * @param array $vars
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  */
18
  function flush( $args = array(), $vars = array() ) {
19
  $args = array_unique( $args );
@@ -22,6 +75,26 @@ class W3TotalCache_Command extends \WP_CLI_Command {
22
  $cache_type = array_shift( $args );
23
 
24
  switch ( $cache_type ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  case 'db':
26
  case 'database':
27
  try {
@@ -57,12 +130,10 @@ class W3TotalCache_Command extends \WP_CLI_Command {
57
  break;
58
 
59
  case 'post':
60
- default:
61
  if ( isset( $vars['post_id'] ) ) {
62
  if ( is_numeric( $vars['post_id'] ) ) {
63
  try {
64
- $w3_cacheflush = Dispatcher::component( 'CacheFlush' );
65
- $w3_cacheflush->flush_post( $vars['post_id'] );
66
  }
67
  catch ( \Exception $e ) {
68
  \WP_CLI::error( __( 'Flushing the page from cache failed.', 'w3-total-cache' ) );
@@ -71,48 +142,164 @@ class W3TotalCache_Command extends \WP_CLI_Command {
71
  } else {
72
  \WP_CLI::error( __( 'This is not a valid post id.', 'w3-total-cache' ) );
73
  }
74
-
75
- w3tc_flush_post( $vars['post_id'] );
76
  }
77
  elseif ( isset( $vars['permalink'] ) ) {
78
- $id = url_to_postid( $vars['permalink'] );
79
-
80
- if ( is_numeric( $id ) ) {
81
- try {
82
- $w3_cacheflush = Dispatcher::component( 'CacheFlush' );
83
- $w3_cacheflush->flush_post( $id );
84
- }
85
- catch ( \Exception $e ) {
86
- \WP_CLI::error( __( 'Flushing the page from cache failed.', 'w3-total-cache' ) );
87
- }
88
- \WP_CLI::success( __( 'The page is flushed from cache successfully.', 'w3-total-cache' ) );
89
- } else {
90
- \WP_CLI::error( __( 'There is no post with this permalink.', 'w3-total-cache' ) );
91
  }
 
 
 
 
92
  } else {
93
  if ( isset( $flushed_page_cache ) && $flushed_page_cache )
94
  break;
95
 
96
- $flushed_page_cache = true;
97
  try {
98
- $w3_cacheflush = Dispatcher::component( 'CacheFlush' );
99
- $w3_cacheflush->flush_posts();
100
  }
101
  catch ( \Exception $e ) {
102
  \WP_CLI::error( __( 'Flushing the page cache failed.', 'w3-total-cache' ) );
103
  }
104
  \WP_CLI::success( __( 'The page cache is flushed successfully.', 'w3-total-cache' ) );
105
  }
 
 
 
 
106
  }
107
  } while ( !empty( $args ) );
108
  }
109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
  /**
112
- * Update query string function
113
  */
114
  function querystring() {
115
-
116
  try {
117
  $w3_querystring = Dispatcher::component( 'CacheFlush' );
118
  $w3_querystring->browsercache_flush();
@@ -128,9 +315,7 @@ class W3TotalCache_Command extends \WP_CLI_Command {
128
  }
129
 
130
  /**
131
- * Purge URL's from cdn and varnish if enabled
132
- *
133
- * @param array $args
134
  */
135
  function cdn_purge( $args = array() ) {
136
  $purgeitems = array();
@@ -196,7 +381,7 @@ class W3TotalCache_Command extends \WP_CLI_Command {
196
  }
197
 
198
  /**
199
- * Tell opcache to reload PHP files
200
  *
201
  * @param array $args
202
  */
@@ -239,7 +424,7 @@ class W3TotalCache_Command extends \WP_CLI_Command {
239
  }
240
 
241
  /**
242
- * triggers PgCache Garbage Cleanup
243
  */
244
  function pgcache_cleanup() {
245
  try {
@@ -253,62 +438,9 @@ class W3TotalCache_Command extends \WP_CLI_Command {
253
  \WP_CLI::success( __( 'PageCache Garbage cleanup triggered successfully.',
254
  'w3-total-cache' ) );
255
  }
 
256
 
257
- /**
258
- * triggers PgCache Garbage Cleanup
259
- */
260
- function fix_environment( $args = array(), $vars = array() ) {
261
- $server_type = array_shift( $args );
262
- switch ( $server_type ) {
263
- case 'apache':
264
- $_SERVER['SERVER_SOFTWARE'] = 'Apache';
265
- break;
266
- case 'nginx':
267
- $_SERVER['SERVER_SOFTWARE'] = 'nginx';
268
- break;
269
- }
270
-
271
- try {
272
- $config = Dispatcher::config();
273
- $environment = Dispatcher::component( 'Root_Environment' );
274
- $environment->fix_in_wpadmin( $config, true );
275
- } catch ( Util_Environment_Exceptions $e ) {
276
- \WP_CLI::error( __( 'Environment adjustment failed with error', 'w3-total-cache' ),
277
- $e->getCombinedMessage() );
278
- }
279
-
280
- \WP_CLI::success( __( 'Environment adjusted.', 'w3-total-cache' ) );
281
- }
282
 
283
- /**
284
- * Help function for this command
285
- */
286
- public static function help() {
287
- \WP_CLI::line( <<<EOB
288
- usage: wp w3-total-cache flush [post|database|minify|object] [--post_id=<post-id>] [--permalink=<post-permalink>]
289
- or : wp w3-total-cache querystring
290
- or : wp w3-total-cache cdn_purge <file> [<file2>]...
291
- or : wp w3-total-cache pgcache_cleanup
292
-
293
- flush flushes whole cache or specific items based on provided arguments
294
- querystring update query string for all static files
295
- cdn_purge Purges command line provided files from Varnish and the CDN
296
- pgcache_cleanup Generally triggered from a cronjob, allows for manual Garbage collection of page cache to be triggered
297
- opcache_flush_file SNS/local file.php Tells opcache to compile files
298
- opcache_flush SNS/local expression Tells opcache to delete all files
299
- fix_environment Creates missing files, writes apache/nginx rules. Subcommand defines server type:
300
- apache create rules for apache server
301
- nginx create rules for nginx server
302
- Available flush sub-commands:
303
- --post_id=<id> flush a specific post ID
304
- --permalink=<post-permalink> flush a specific permalink
305
- database flush the database cache
306
- object flush the object cache
307
- minify flush the minify cache
308
- EOB
309
- );
310
- }
311
- }
312
 
313
  if ( method_exists( '\WP_CLI', 'add_command' ) ) {
314
  \WP_CLI::add_command( 'w3-total-cache', '\W3TC\W3TotalCache_Command' );
2
  namespace W3TC;
3
 
4
  /**
5
+ * The W3 Total Cache plugin integration
6
  *
7
  * @package wp-cli
8
  * @subpackage commands/third-party
9
  */
10
  class W3TotalCache_Command extends \WP_CLI_Command {
11
+ /**
12
+ * Creates missing files, writes apache/nginx rules.
13
+ *
14
+ * ## OPTIONS
15
+ * [<server>]
16
+ * : Subcommand defines server type:
17
+ * apache create rules for apache server
18
+ * nginx create rules for nginx server
19
+ */
20
+ function fix_environment( $args = array(), $vars = array() ) {
21
+ $server_type = array_shift( $args );
22
+ switch ( $server_type ) {
23
+ case 'apache':
24
+ $_SERVER['SERVER_SOFTWARE'] = 'Apache';
25
+ break;
26
+ case 'nginx':
27
+ $_SERVER['SERVER_SOFTWARE'] = 'nginx';
28
+ break;
29
+ }
30
+
31
+ try {
32
+ $config = Dispatcher::config();
33
+ $environment = Dispatcher::component( 'Root_Environment' );
34
+ $environment->fix_in_wpadmin( $config, true );
35
+ } catch ( Util_Environment_Exceptions $e ) {
36
+ \WP_CLI::error( __( 'Environment adjustment failed with error', 'w3-total-cache' ),
37
+ $e->getCombinedMessage() );
38
+ }
39
+
40
+ \WP_CLI::success( __( 'Environment adjusted.', 'w3-total-cache' ) );
41
+ }
42
+
43
+
44
 
45
  /**
46
+ * Clear something from the cache.
47
  *
48
+ * ## OPTIONS
49
+ * <cache>
50
+ * : Cache to flush
51
+ * all flush all caches
52
+ * posts flush posts (pagecache and further)
53
+ * post flush the page cache
54
+ * database flush the database cache
55
+ * object flush the object cache
56
+ * minify flush the minify cache
57
+ *
58
+ * [--post_id=<id>]
59
+ * : flush a specific post ID
60
+ *
61
+ * [--permalink=<post-permalink>]
62
+ * : flush a specific permalink
63
+ *
64
+ * ## EXAMPLES
65
+ * # Flush all
66
+ * $ wp w3-total-cache flush all
67
+ *
68
+ * # Flush pagecache and reverse proxies
69
+ * $ wp w3-total-cache flush posts
70
  */
71
  function flush( $args = array(), $vars = array() ) {
72
  $args = array_unique( $args );
75
  $cache_type = array_shift( $args );
76
 
77
  switch ( $cache_type ) {
78
+ case 'all':
79
+ try {
80
+ w3tc_flush_all();
81
+ }
82
+ catch ( \Exception $e ) {
83
+ \WP_CLI::error( __( 'Flushing all failed.', 'w3-total-cache' ) );
84
+ }
85
+ \WP_CLI::success( __( 'Everything flushed successfully.', 'w3-total-cache' ) );
86
+ break;
87
+
88
+ case 'posts':
89
+ try {
90
+ w3tc_flush_posts();
91
+ }
92
+ catch ( \Exception $e ) {
93
+ \WP_CLI::error( __( 'Flushing posts/pages failed.', 'w3-total-cache' ) );
94
+ }
95
+ \WP_CLI::success( __( 'Posts/pages flushed successfully.', 'w3-total-cache' ) );
96
+ break;
97
+
98
  case 'db':
99
  case 'database':
100
  try {
130
  break;
131
 
132
  case 'post':
 
133
  if ( isset( $vars['post_id'] ) ) {
134
  if ( is_numeric( $vars['post_id'] ) ) {
135
  try {
136
+ w3tc_flush_post( $vars['post_id'] );
 
137
  }
138
  catch ( \Exception $e ) {
139
  \WP_CLI::error( __( 'Flushing the page from cache failed.', 'w3-total-cache' ) );
142
  } else {
143
  \WP_CLI::error( __( 'This is not a valid post id.', 'w3-total-cache' ) );
144
  }
 
 
145
  }
146
  elseif ( isset( $vars['permalink'] ) ) {
147
+ try {
148
+ w3tc_flush_url( $vars['permalink'] );
 
 
 
 
 
 
 
 
 
 
 
149
  }
150
+ catch ( \Exception $e ) {
151
+ \WP_CLI::error( __( 'Flushing the page from cache failed.', 'w3-total-cache' ) );
152
+ }
153
+ \WP_CLI::success( __( 'The page is flushed from cache successfully.', 'w3-total-cache' ) );
154
  } else {
155
  if ( isset( $flushed_page_cache ) && $flushed_page_cache )
156
  break;
157
 
 
158
  try {
159
+ w3tc_flush_posts();
 
160
  }
161
  catch ( \Exception $e ) {
162
  \WP_CLI::error( __( 'Flushing the page cache failed.', 'w3-total-cache' ) );
163
  }
164
  \WP_CLI::success( __( 'The page cache is flushed successfully.', 'w3-total-cache' ) );
165
  }
166
+ break;
167
+
168
+ default:
169
+ \WP_CLI::error( __( 'Not specified what to flush', 'w3-total-cache' ) );
170
  }
171
  } while ( !empty( $args ) );
172
  }
173
 
174
+ /**
175
+ * Get or set option.
176
+ *
177
+ * Options modifications don't update your .htaccess automatically.
178
+ * Use fix_environment command afterwards to do it.
179
+ *
180
+ * ## OPTIONS
181
+ * <operation>
182
+ * : operation to do
183
+ * get get option value
184
+ * set set option value
185
+ * <name>
186
+ * : option name
187
+ *
188
+ * [<value>]
189
+ * : (for set operation) Value to set
190
+ *
191
+ * [--state]
192
+ * : use state, not config
193
+ * state is used for backend notifications
194
+ *
195
+ * [--master]
196
+ * : use master config/state
197
+ *
198
+ * [--type=<type>]
199
+ * : type of data used boolean/string/integer/array. Default string
200
+ *
201
+ * [--delimiter=<delimiter>]
202
+ * : delimiter to use for array type values
203
+ *
204
+ * ## EXAMPLES
205
+ * # get if pagecache enabled
206
+ * $ wp w3-total-cache option get pgcache.enabled --type=boolean
207
+ *
208
+ * # enable pagecache
209
+ * $ wp w3-total-cache option set pgcache.enabled true --type=boolean
210
+ *
211
+ * # don't show wp-content permissions notification
212
+ * $ wp w3-total-cache option set common.hide_note_wp_content_permissions true --state --type=boolean
213
+ */
214
+ function option( $args = array(), $vars = array() ) {
215
+ $op = array_shift( $args );
216
+ $name = array_shift( $args );
217
+
218
+ if ( empty( $name ) ) {
219
+ \WP_CLI::error( __( '<name> parameter is not specified', 'w3-total-cache' ) );
220
+ return;
221
+ }
222
+ if ( strpos( $name, '::' ) !== FALSE ) {
223
+ $name = explode('::', $name);
224
+ }
225
+
226
+ $c = null;
227
+ if ( isset( $vars['state'] ) ) {
228
+ if ( isset( $vars['master'] ) )
229
+ $c = Dispatcher::config_state_master();
230
+ else
231
+ $c = Dispatcher::config_state();
232
+ } else {
233
+ if ( isset( $vars['master'] ) )
234
+ $c = Dispatcher::config_master();
235
+ else
236
+ $c = Dispatcher::config();
237
+ }
238
+
239
+ if ( $op == 'get') {
240
+ $type =( isset( $vars['type'] ) ? $vars['type'] : 'string' );
241
+
242
+ if ( $type == 'boolean' )
243
+ $v = $c->get_boolean( $name ) ? 'true' : 'false';
244
+ elseif ( $type == 'integer' )
245
+ $v = $c->get_integer( $name );
246
+ elseif ( $type == 'string' )
247
+ $v = $c->get_string( $name );
248
+ elseif ( $type == 'array' )
249
+ $v = json_encode( $c->get_array( $name ), JSON_PRETTY_PRINT );
250
+ else {
251
+ \WP_CLI::error( __( 'Unknown type ' . $type, 'w3-total-cache' ) );
252
+ return;
253
+ }
254
+
255
+ echo $v . "\n";
256
+ } elseif ( $op == 'set' ) {
257
+ $type =( isset( $vars['type'] ) ? $vars['type'] : 'string' );
258
+
259
+ if ( count( $args ) <= 0 ) {
260
+ \WP_CLI::error( __( '<value> parameter is not specified', 'w3-total-cache' ) );
261
+ return;
262
+ }
263
+ $value = array_shift( $args );
264
+
265
+ if ( $type == 'boolean' ) {
266
+ if ( $value == 'true' || $value == '1' || $value == 'on' )
267
+ $v = true;
268
+ elseif ( $value == 'false' || $value == '0' || $value == 'off' )
269
+ $v = false;
270
+ else {
271
+ \WP_CLI::error( __( '<value> parameter ' . $value . ' is not boolean', 'w3-total-cache' ) );
272
+ return;
273
+ }
274
+ } elseif ( $type == 'integer' )
275
+ $v = (integer)$value;
276
+ elseif ( $type == 'string' )
277
+ $v = $value;
278
+ elseif ( $type == 'array' ) {
279
+ $delimiter =( isset( $vars['delimiter'] ) ? $vars['delimiter'] : ',' );
280
+ $v = explode($delimiter, $value );
281
+ } else {
282
+ \WP_CLI::error( __( 'Unknown type ' . $type, 'w3-total-cache' ) );
283
+ return;
284
+ }
285
+
286
+ try {
287
+ $c->set( $name, $v );
288
+ $c->save();
289
+ \WP_CLI::success( __( 'Option updated successfully.', 'w3-total-cache' ) );
290
+ } catch ( \Exception $e ) {
291
+ \WP_CLI::error( __( 'Option value update failed.', 'w3-total-cache' ) );
292
+ }
293
+
294
+ } else {
295
+ \WP_CLI::error( __( '<operation> parameter is not specified', 'w3-total-cache' ) );
296
+ }
297
+ }
298
 
299
  /**
300
+ * Update query string for all static files
301
  */
302
  function querystring() {
 
303
  try {
304
  $w3_querystring = Dispatcher::component( 'CacheFlush' );
305
  $w3_querystring->browsercache_flush();
315
  }
316
 
317
  /**
318
+ * Purges URL's from cdn and varnish if enabled
 
 
319
  */
320
  function cdn_purge( $args = array() ) {
321
  $purgeitems = array();
381
  }
382
 
383
  /**
384
+ * SNS/local file.php Tells opcache to compile files
385
  *
386
  * @param array $args
387
  */
424
  }
425
 
426
  /**
427
+ * Generally triggered from a cronjob, allows for manual Garbage collection of page cache to be triggered
428
  */
429
  function pgcache_cleanup() {
430
  try {
438
  \WP_CLI::success( __( 'PageCache Garbage cleanup triggered successfully.',
439
  'w3-total-cache' ) );
440
  }
441
+ }
442
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444
 
445
  if ( method_exists( '\WP_CLI', 'add_command' ) ) {
446
  \WP_CLI::add_command( 'w3-total-cache', '\W3TC\W3TotalCache_Command' );
Config.php CHANGED
@@ -21,6 +21,7 @@ class Config {
21
 
22
  private $_md5;
23
  private $_data;
 
24
 
25
 
26
 
@@ -34,7 +35,7 @@ class Config {
34
  // problems with APC, ZendCache, and WSOD in a case of
35
  // broken config file
36
  $content = @file_get_contents( $filename );
37
- $config = @json_decode( $content, true );
38
 
39
  if ( is_array( $config ) )
40
  return $config;
@@ -50,7 +51,7 @@ class Config {
50
  * Stored in this class to limit class loading
51
  */
52
  static public function util_config_filename( $blog_id, $preview ) {
53
- $postfix = ( $preview ? '-preview' : '' ) . '.json';
54
 
55
  if ( $blog_id <= 0 )
56
  return W3TC_CONFIG_DIR . '/master' . $postfix;
@@ -65,7 +66,7 @@ class Config {
65
  * Stored in this class to limit class loading
66
  * v<0.9.5
67
  */
68
- static public function util_config_filename_legacy( $blog_id, $preview ) {
69
  $postfix = ( $preview ? '-preview' : '' ) . '.php';
70
 
71
  if ( $blog_id <= 0 )
@@ -74,6 +75,20 @@ class Config {
74
  return W3TC_CONFIG_DIR . '/' . sprintf( '%06d', $blog_id ) . $postfix;
75
  }
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
 
79
  public function __construct( $blog_id = null ) {
@@ -248,6 +263,10 @@ class Config {
248
  return $this->_is_master;
249
  }
250
 
 
 
 
 
251
 
252
 
253
  /**
@@ -358,6 +377,7 @@ class Config {
358
  }
359
 
360
  $this->_data = $data;
 
361
  }
362
 
363
 
@@ -369,5 +389,6 @@ class Config {
369
  $c = new ConfigCompiler( $this->_blog_id, $this->_preview );
370
  $c->load();
371
  $this->_data = $c->get_data();
 
372
  }
373
  }
21
 
22
  private $_md5;
23
  private $_data;
24
+ private $_compiled;
25
 
26
 
27
 
35
  // problems with APC, ZendCache, and WSOD in a case of
36
  // broken config file
37
  $content = @file_get_contents( $filename );
38
+ $config = @json_decode( substr( $content, 14 ), true );
39
 
40
  if ( is_array( $config ) )
41
  return $config;
51
  * Stored in this class to limit class loading
52
  */
53
  static public function util_config_filename( $blog_id, $preview ) {
54
+ $postfix = ( $preview ? '-preview' : '' ) . '.php';
55
 
56
  if ( $blog_id <= 0 )
57
  return W3TC_CONFIG_DIR . '/master' . $postfix;
66
  * Stored in this class to limit class loading
67
  * v<0.9.5
68
  */
69
+ static public function util_config_filename_legacy_v1( $blog_id, $preview ) {
70
  $postfix = ( $preview ? '-preview' : '' ) . '.php';
71
 
72
  if ( $blog_id <= 0 )
75
  return W3TC_CONFIG_DIR . '/' . sprintf( '%06d', $blog_id ) . $postfix;
76
  }
77
 
78
+ /*
79
+ * Returns config filename
80
+ * Stored in this class to limit class loading
81
+ * v = 0.9.5 - 0.9.5.1
82
+ */
83
+ static public function util_config_filename_legacy_v2( $blog_id, $preview ) {
84
+ $postfix = ( $preview ? '-preview' : '' ) . '.json';
85
+
86
+ if ( $blog_id <= 0 )
87
+ return W3TC_CONFIG_DIR . '/master' . $postfix;
88
+ else
89
+ return W3TC_CONFIG_DIR . '/' . sprintf( '%06d', $blog_id ) . $postfix;
90
+ }
91
+
92
 
93
 
94
  public function __construct( $blog_id = null ) {
263
  return $this->_is_master;
264
  }
265
 
266
+ public function is_compiled() {
267
+ return $this->_compiled;
268
+ }
269
+
270
 
271
 
272
  /**
377
  }
378
 
379
  $this->_data = $data;
380
+ $this->_compiled = false;
381
  }
382
 
383
 
389
  $c = new ConfigCompiler( $this->_blog_id, $this->_preview );
390
  $c->load();
391
  $this->_data = $c->get_data();
392
+ $this->_compiled = true;
393
  }
394
  }
ConfigCompiler.php CHANGED
@@ -74,7 +74,7 @@ class ConfigCompiler {
74
  * Reads config from file and returns it's content as array (or null)
75
  * Stored in this class to limit class loading
76
  */
77
- static private function util_array_from_file_legacy( $filename ) {
78
  if ( file_exists( $filename ) && is_readable( $filename ) ) {
79
  // including file directly instead of read+eval causes constant
80
  // problems with APC, ZendCache, and WSOD in a case of
@@ -91,6 +91,27 @@ class ConfigCompiler {
91
 
92
 
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  public function __construct( $blog_id, $preview ) {
95
  $this->_blog_id = $blog_id;
96
  $this->_preview = $preview;
@@ -117,11 +138,18 @@ class ConfigCompiler {
117
  $data = Config::util_array_from_file( $master_filename );
118
  }
119
 
120
- // try to get legacy data
121
  if ( is_null( $data ) ) {
122
- $master_filename = Config::util_config_filename_legacy( 0,
123
  $this->_preview );
124
- $data = self::util_array_from_file_legacy( $master_filename );
 
 
 
 
 
 
 
125
  }
126
 
127
  if ( is_array( $data ) ) {
@@ -145,11 +173,18 @@ class ConfigCompiler {
145
  $data = Config::util_array_from_file( $child_filename );
146
  }
147
 
148
- // try to get legacy data
 
 
 
 
 
 
 
149
  if ( is_null( $data ) ) {
150
- $child_filename = Config::util_config_filename_legacy(
151
  $this->_blog_id, $this->_preview );
152
- $data = self::util_array_from_file_legacy( $child_filename );
153
  }
154
 
155
  if ( is_array( $data ) ) {
@@ -203,7 +238,7 @@ class ConfigCompiler {
203
  else // for older php versions
204
  $config = json_encode( $data );
205
 
206
- Util_File::file_put_contents_atomic( $filename, $config );
207
  }
208
 
209
 
74
  * Reads config from file and returns it's content as array (or null)
75
  * Stored in this class to limit class loading
76
  */
77
+ static private function util_array_from_file_legacy_v1( $filename ) {
78
  if ( file_exists( $filename ) && is_readable( $filename ) ) {
79
  // including file directly instead of read+eval causes constant
80
  // problems with APC, ZendCache, and WSOD in a case of
91
 
92
 
93
 
94
+ /**
95
+ * Reads config from file and returns it's content as array (or null)
96
+ * Stored in this class to limit class loading
97
+ */
98
+ static private function util_array_from_file_legacy_v2( $filename ) {
99
+ if ( file_exists( $filename ) && is_readable( $filename ) ) {
100
+ // including file directly instead of read+eval causes constant
101
+ // problems with APC, ZendCache, and WSOD in a case of
102
+ // broken config file
103
+ $content = @file_get_contents( $filename );
104
+ $config = @json_decode( $content, true );
105
+
106
+ if ( is_array( $config ) )
107
+ return $config;
108
+ }
109
+
110
+ return null;
111
+ }
112
+
113
+
114
+
115
  public function __construct( $blog_id, $preview ) {
116
  $this->_blog_id = $blog_id;
117
  $this->_preview = $preview;
138
  $data = Config::util_array_from_file( $master_filename );
139
  }
140
 
141
+ // try to get legacy v2 data
142
  if ( is_null( $data ) ) {
143
+ $master_filename = Config::util_config_filename_legacy_v2( 0,
144
  $this->_preview );
145
+ $data = self::util_array_from_file_legacy_v2( $master_filename );
146
+ }
147
+
148
+ // try to get legacy v1 data
149
+ if ( is_null( $data ) ) {
150
+ $master_filename = Config::util_config_filename_legacy_v1( 0,
151
+ $this->_preview );
152
+ $data = self::util_array_from_file_legacy_v1( $master_filename );
153
  }
154
 
155
  if ( is_array( $data ) ) {
173
  $data = Config::util_array_from_file( $child_filename );
174
  }
175
 
176
+ // try to get legacy v2 data
177
+ if ( is_null( $data ) ) {
178
+ $child_filename = Config::util_config_filename_legacy_v2(
179
+ $this->_blog_id, $this->_preview );
180
+ $data = self::util_array_from_file_legacy_v2( $child_filename );
181
+ }
182
+
183
+ // try to get legacy v1 data
184
  if ( is_null( $data ) ) {
185
+ $child_filename = Config::util_config_filename_legacy_v1(
186
  $this->_blog_id, $this->_preview );
187
+ $data = self::util_array_from_file_legacy_v1( $child_filename );
188
  }
189
 
190
  if ( is_array( $data ) ) {
238
  else // for older php versions
239
  $config = json_encode( $data );
240
 
241
+ Util_File::file_put_contents_atomic( $filename, '<?php exit; ?>' . $config );
242
  }
243
 
244
 
ConfigKeys.php CHANGED
@@ -160,6 +160,14 @@ $keys = array(
160
  'type' => 'boolean',
161
  'default' => false
162
  ),
 
 
 
 
 
 
 
 
163
  'objectcache.engine' => array(
164
  'type' => 'string',
165
  'default' => 'file'
@@ -351,7 +359,8 @@ $keys = array(
351
  'Last-Modified',
352
  'Content-Type',
353
  'X-Pingback',
354
- 'P3P'
 
355
  )
356
  ),
357
  'pgcache.compatibility' => array(
@@ -656,6 +665,10 @@ $keys = array(
656
  'RSPEAK_'
657
  )
658
  ),
 
 
 
 
659
  'minify.css.enable' => array(
660
  'type' => 'boolean',
661
  'default' => true
@@ -664,7 +677,7 @@ $keys = array(
664
  'type' => 'string',
665
  'default' => 'css'
666
  ),
667
- 'minify.css.combine' => array(
668
  'type' => 'boolean',
669
  'default' => false
670
  ),
@@ -688,6 +701,10 @@ $keys = array(
688
  'type' => 'array',
689
  'default' => array()
690
  ),
 
 
 
 
691
  'minify.js.enable' => array(
692
  'type' => 'boolean',
693
  'default' => true
@@ -880,6 +897,10 @@ $keys = array(
880
  'type' => 'array',
881
  'default' => array( '' )
882
  ),
 
 
 
 
883
 
884
  'cdn.configuration_overloaded' => array(
885
  'type' => 'boolean',
@@ -1708,7 +1729,7 @@ $keys = array(
1708
  ),
1709
  'common.track_usage' => array(
1710
  'type' => 'boolean',
1711
- 'default' => false
1712
  ),
1713
  'common.tweeted' => array(
1714
  'type' => 'boolean',
160
  'type' => 'boolean',
161
  'default' => false
162
  ),
163
+ 'objectcache.enabled_for_wp_admin' => array(
164
+ 'type' => 'boolean',
165
+ 'default' => true
166
+ ),
167
+ 'objectcache.fallback_transients' => array(
168
+ 'type' => 'boolean',
169
+ 'default' => true
170
+ ),
171
  'objectcache.engine' => array(
172
  'type' => 'string',
173
  'default' => 'file'
359
  'Last-Modified',
360
  'Content-Type',
361
  'X-Pingback',
362
+ 'P3P',
363
+ 'Link'
364
  )
365
  ),
366
  'pgcache.compatibility' => array(
665
  'RSPEAK_'
666
  )
667
  ),
668
+ 'minify.css.combine' => array(
669
+ 'type' => 'boolean',
670
+ 'default' => false
671
+ ),
672
  'minify.css.enable' => array(
673
  'type' => 'boolean',
674
  'default' => true
677
  'type' => 'string',
678
  'default' => 'css'
679
  ),
680
+ 'minify.css.http2push' => array(
681
  'type' => 'boolean',
682
  'default' => false
683
  ),
701
  'type' => 'array',
702
  'default' => array()
703
  ),
704
+ 'minify.js.http2push' => array(
705
+ 'type' => 'boolean',
706
+ 'default' => false
707
+ ),
708
  'minify.js.enable' => array(
709
  'type' => 'boolean',
710
  'default' => true
897
  'type' => 'array',
898
  'default' => array( '' )
899
  ),
900
+ 'minify.cache.files_regexp' => array(
901
+ 'type' => 'boolean',
902
+ 'default' => false
903
+ ),
904
 
905
  'cdn.configuration_overloaded' => array(
906
  'type' => 'boolean',
1729
  ),
1730
  'common.track_usage' => array(
1731
  'type' => 'boolean',
1732
+ 'default' => true
1733
  ),
1734
  'common.tweeted' => array(
1735
  'type' => 'boolean',
DbCache_Core.php CHANGED
@@ -15,8 +15,8 @@ class DbCache_Core {
15
  'servers' => $c->get_array( 'dbcache.memcached.servers' ),
16
  'persistent' => $c->get_boolean( 'dbcache.memcached.persistent' ),
17
  'aws_autodiscovery' => $c->get_boolean( 'dbcache.memcached.aws_autodiscovery' ),
18
- 'username' => $c->get_boolean( 'dbcache.memcached.username' ),
19
- 'password' => $c->get_boolean( 'dbcache.memcached.password' )
20
  );
21
  break;
22
 
@@ -24,8 +24,8 @@ class DbCache_Core {
24
  $engineConfig = array(
25
  'servers' => $c->get_array( 'dbcache.redis.servers' ),
26
  'persistent' => $c->get_boolean( 'dbcache.redis.persistent' ),
27
- 'dbid' => $c->get_boolean( 'dbcache.redis.dbid' ),
28
- 'password' => $c->get_boolean( 'dbcache.redis.password' )
29
  );
30
  break;
31
 
15
  'servers' => $c->get_array( 'dbcache.memcached.servers' ),
16
  'persistent' => $c->get_boolean( 'dbcache.memcached.persistent' ),
17
  'aws_autodiscovery' => $c->get_boolean( 'dbcache.memcached.aws_autodiscovery' ),
18
+ 'username' => $c->get_string( 'dbcache.memcached.username' ),
19
+ 'password' => $c->get_string( 'dbcache.memcached.password' )
20
  );
21
  break;
22
 
24
  $engineConfig = array(
25
  'servers' => $c->get_array( 'dbcache.redis.servers' ),
26
  'persistent' => $c->get_boolean( 'dbcache.redis.persistent' ),
27
+ 'dbid' => $c->get_integer( 'dbcache.redis.dbid' ),
28
+ 'password' => $c->get_string( 'dbcache.redis.password' )
29
  );
30
  break;
31
 
DbCache_Plugin_Admin.php CHANGED
@@ -22,16 +22,16 @@ class DbCache_Plugin_Admin {
22
  if ( $c->get_string( 'dbcache.engine' ) == 'memcached' ) {
23
  $summary['memcached_servers']['dbcache'] = array(
24
  'servers' => $c->get_array( 'dbcache.memcached.servers' ),
25
- 'username' => $c->get_boolean( 'dbcache.memcached.username' ),
26
- 'password' => $c->get_boolean( 'dbcache.memcached.password' ),
27
  'name' => __( 'Database Cache', 'w3-total-cache' )
28
  );
29
  } elseif ( $c->get_string( 'dbcache.engine' ) == 'redis' ) {
30
  $summary['redis_servers']['dbcache'] = array(
31
  'servers' => $c->get_array( 'dbcache.redis.servers' ),
32
  'username' => $c->get_boolean( 'dbcache.redis.username' ),
33
- 'dbid' => $c->get_boolean( 'dbcache.redis.dbid' ),
34
- 'password' => $c->get_boolean( 'dbcache.redis.password' ),
35
  'name' => __( 'Database Cache', 'w3-total-cache' )
36
  );
37
  }
22
  if ( $c->get_string( 'dbcache.engine' ) == 'memcached' ) {
23
  $summary['memcached_servers']['dbcache'] = array(
24
  'servers' => $c->get_array( 'dbcache.memcached.servers' ),
25
+ 'username' => $c->get_string( 'dbcache.memcached.username' ),
26
+ 'password' => $c->get_string( 'dbcache.memcached.password' ),
27
  'name' => __( 'Database Cache', 'w3-total-cache' )
28
  );
29
  } elseif ( $c->get_string( 'dbcache.engine' ) == 'redis' ) {
30
  $summary['redis_servers']['dbcache'] = array(
31
  'servers' => $c->get_array( 'dbcache.redis.servers' ),
32
  'username' => $c->get_boolean( 'dbcache.redis.username' ),
33
+ 'dbid' => $c->get_integer( 'dbcache.redis.dbid' ),
34
+ 'password' => $c->get_string( 'dbcache.redis.password' ),
35
  'name' => __( 'Database Cache', 'w3-total-cache' )
36
  );
37
  }
DbCache_WpdbInjection_QueryCaching.php CHANGED
@@ -280,8 +280,8 @@ class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
280
  'servers' => $this->_config->get_array( 'dbcache.memcached.servers' ),
281
  'persistent' => $this->_config->get_boolean( 'dbcache.memcached.persistent' ),
282
  'aws_autodiscovery' => $this->_config->get_boolean( 'dbcache.memcached.aws_autodiscovery' ),
283
- 'username' => $this->_config->get_boolean( 'dbcache.memcached.username' ),
284
- 'password' => $this->_config->get_boolean( 'dbcache.memcached.password' )
285
  );
286
  break;
287
 
@@ -289,8 +289,8 @@ class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
289
  $engineConfig = array(
290
  'servers' => $this->_config->get_array( 'dbcache.redis.servers' ),
291
  'persistent' => $this->_config->get_boolean( 'dbcache.redis.persistent' ),
292
- 'dbid' => $this->_config->get_boolean( 'dbcache.redis.dbid' ),
293
- 'password' => $this->_config->get_boolean( 'dbcache.redis.password' )
294
  );
295
  break;
296
 
@@ -363,7 +363,8 @@ class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
363
  $ajax_skip = false;
364
  if ( defined( 'DOING_AJAX' ) ) {
365
  // wp_admin is always defined for ajax requests, check by referrer
366
- if ( strpos( $_SERVER['HTTP_REFERER'], '/wp-admin/' ) === false )
 
367
  $ajax_skip = true;
368
  }
369
 
280
  'servers' => $this->_config->get_array( 'dbcache.memcached.servers' ),
281
  'persistent' => $this->_config->get_boolean( 'dbcache.memcached.persistent' ),
282
  'aws_autodiscovery' => $this->_config->get_boolean( 'dbcache.memcached.aws_autodiscovery' ),
283
+ 'username' => $this->_config->get_string( 'dbcache.memcached.username' ),
284
+ 'password' => $this->_config->get_string( 'dbcache.memcached.password' )
285
  );
286
  break;
287
 
289
  $engineConfig = array(
290
  'servers' => $this->_config->get_array( 'dbcache.redis.servers' ),
291
  'persistent' => $this->_config->get_boolean( 'dbcache.redis.persistent' ),
292
+ 'dbid' => $this->_config->get_integer( 'dbcache.redis.dbid' ),
293
+ 'password' => $this->_config->get_string( 'dbcache.redis.password' )
294
  );
295
  break;
296
 
363
  $ajax_skip = false;
364
  if ( defined( 'DOING_AJAX' ) ) {
365
  // wp_admin is always defined for ajax requests, check by referrer
366
+ if ( isset( $_SERVER['HTTP_REFERER'] ) &&
367
+ strpos( $_SERVER['HTTP_REFERER'], '/wp-admin/' ) === false )
368
  $ajax_skip = true;
369
  }
370
 
Dispatcher.php CHANGED
@@ -104,13 +104,12 @@ class Dispatcher {
104
 
105
  $data = $minify->process( $short_filename, true );
106
 
107
- if ( !file_exists( $filename ) &&
108
- isset( $data['content']['content'] ) ) {
109
 
110
  if ( !file_exists( dirname( $filename ) ) )
111
- Util_File::mkdir_from( dirname( $filename ), W3TC_CACHE_DIR );
112
  }
113
- @file_put_contents( $filename, $data['content']['content'] );
114
  }
115
  }
116
 
104
 
105
  $data = $minify->process( $short_filename, true );
106
 
107
+ if ( !file_exists( $filename ) && isset( $data['content'] ) ) {
 
108
 
109
  if ( !file_exists( dirname( $filename ) ) )
110
+ Util_File::mkdir_from_safe( dirname( $filename ), W3TC_CACHE_DIR );
111
  }
112
+ @file_put_contents( $filename, $data['content'] );
113
  }
114
  }
115
 
Enterprise_Dbcache_WpdbInjection_Cluster.php CHANGED
@@ -7,7 +7,7 @@ namespace W3TC;
7
  */
8
  class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
9
  /**
10
- * Whether to check with fsockopen prior to mysql_connect.
11
  *
12
  * @var bool
13
  */
@@ -21,7 +21,7 @@ class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
21
  var $min_tries = 3;
22
 
23
  /**
24
- * Whether to use mysql_pconnect instead of mysql_connect
25
  *
26
  * @var bool
27
  */
@@ -256,7 +256,6 @@ class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
256
  * @return resource mysql database connection
257
  */
258
  function db_connect( $query = '', $use_master = null ) {
259
- $connect_function = $this->persistent ? 'mysql_pconnect' : 'mysql_connect';
260
  if ( empty( $this->_cluster_servers ) )
261
  return $this->_db_connect_fallback();
262
 
@@ -345,7 +344,7 @@ class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
345
  // $zone, $index
346
  extract( $zone_index, EXTR_OVERWRITE );
347
 
348
- // $host, $user, $password, $name, $read, $write [, $connect_function], $timeout
349
  extract( $this->_cluster_servers[$dataset][$operation][$zone][$index], EXTR_OVERWRITE );
350
 
351
  // Split host:port into $host and $port
@@ -365,13 +364,16 @@ class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
365
  }
366
 
367
  $dbh = null;
368
- if ( is_null( $tcp_responded ) || $tcp_responded )
369
- $dbh = @ $connect_function( "$host:$port", $user, $password, true );
 
 
 
370
 
371
  $elapsed = $this->wpdb_mixin->timer_stop();
372
 
373
  if ( is_resource( $dbh ) ) {
374
- if ( mysql_select_db( $name, $dbh ) ) {
375
  $this->_connections[$dbhname] = array(
376
  'dbh' => $dbh,
377
  'database_name' => $name );
@@ -441,7 +443,7 @@ class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
441
  if ( !is_resource( $dbh ) )
442
  return null;
443
 
444
- if ( !mysql_ping( $dbh ) ) {
445
  // disconnect (ping failed)
446
  $this->_disconnect( $dbhname );
447
  return null;
@@ -453,7 +455,7 @@ class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
453
  /**
454
  * Sets the connection's character set.
455
  *
456
- * @param resource $dbh The resource given by mysql_connect
457
  * @param string $charset The character set (optional)
458
  * @param string $collate The collation (optional)
459
  */
@@ -463,14 +465,14 @@ class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
463
  if ( !isset( $collate ) )
464
  $collate = $this->wpdb_mixin->collate;
465
  if ( $this->has_cap( 'collation', $dbh ) && !empty( $charset ) ) {
466
- if ( function_exists( 'mysql_set_charset' ) && $this->has_cap( 'set_charset', $dbh ) ) {
467
- mysql_set_charset( $charset, $dbh );
468
  $this->wpdb_mixin->real_escape = true;
469
  } else {
470
  $query = $this->wpdb_mixin->prepare( 'SET NAMES %s', $charset );
471
  if ( !empty( $collate ) )
472
  $query .= $this->wpdb_mixin->prepare( ' COLLATE %s', $collate );
473
- mysql_query( $query, $dbh );
474
  }
475
  }
476
  }
@@ -513,14 +515,14 @@ class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
513
  return false;
514
 
515
  $this->wpdb_mixin->timer_start();
516
- $this->wpdb_mixin->result = mysql_query( $query, $this->wpdb_mixin->dbh );
517
  $elapsed = $this->wpdb_mixin->timer_stop();
518
  ++$this->wpdb_mixin->num_queries;
519
 
520
  if ( preg_match( '/^\s*SELECT\s+SQL_CALC_FOUND_ROWS\s/i', $query ) ) {
521
  if ( false === strpos( $query, "NO_SELECT_FOUND_ROWS" ) ) {
522
  $this->wpdb_mixin->timer_start();
523
- $this->wpdb_mixin->_last_found_rows_result = mysql_query( "SELECT FOUND_ROWS()", $this->wpdb_mixin->dbh );
524
  $elapsed += $this->wpdb_mixin->timer_stop();
525
  ++$this->wpdb_mixin->num_queries;
526
  $query .= "; SELECT FOUND_ROWS()";
@@ -534,17 +536,17 @@ class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
534
  apply_filters( 'after_query', $query );
535
 
536
  // If there is an error then take note of it
537
- if ( $this->wpdb_mixin->last_error = mysql_error( $this->wpdb_mixin->dbh ) ) {
538
  $this->wpdb_mixin->print_error( $this->wpdb_mixin->last_error );
539
  return false;
540
  }
541
 
542
  if ( preg_match( "/^\\s*(insert|delete|update|replace|alter) /i", $query ) ) {
543
- $this->wpdb_mixin->rows_affected = mysql_affected_rows( $this->wpdb_mixin->dbh );
544
 
545
  // Take note of the insert_id
546
  if ( preg_match( "/^\\s*(insert|replace) /i", $query ) ) {
547
- $this->wpdb_mixin->insert_id = mysql_insert_id( $this->wpdb_mixin->dbh );
548
  }
549
  // Return number of rows affected
550
  return $this->wpdb_mixin->rows_affected;
@@ -552,19 +554,19 @@ class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
552
  $i = 0;
553
  $this->wpdb_mixin->col_info = array();
554
  $col_info = array();
555
- while ( $i < @mysql_num_fields( $this->wpdb_mixin->result ) ) {
556
- $col_info[$i] = @mysql_fetch_field( $this->wpdb_mixin->result );
557
  $i++;
558
  }
559
  $this->wpdb_mixin->col_info = $col_info;
560
  $num_rows = 0;
561
  $this->wpdb_mixin->last_result = array();
562
- while ( $row = @mysql_fetch_object( $this->wpdb_mixin->result ) ) {
563
  $this->wpdb_mixin->last_result[$num_rows] = $row;
564
  $num_rows++;
565
  }
566
 
567
- @mysql_free_result( $this->wpdb_mixin->result );
568
 
569
  // Log number of rows the query returned
570
  $this->num_rows = $num_rows;
@@ -584,8 +586,8 @@ class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
584
  function check_database_version( $dbh_or_table = false ) {
585
  global $wp_version;
586
  // Make sure the server has MySQL 4.1.2
587
- $mysql_version = preg_replace( '|[^0-9\.]|', '', $this->wpdb_mixin->db_version( $dbh_or_table ) );
588
- if ( version_compare( $mysql_version, '4.1.2', '<' ) )
589
  return new \WP_Error( 'database_version', sprintf( __( '<strong>ERROR</strong>: WordPress %s requires MySQL 4.1.2 or higher' ), $wp_version ) );
590
  }
591
 
@@ -639,7 +641,7 @@ class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
639
  $dbh = $this->db_connect( "SELECT FROM $dbh_or_table $this->wpdb_mixin->users" );
640
 
641
  if ( $dbh )
642
- return preg_replace( '/[^0-9.].*/', '', mysql_get_server_info( $dbh ) );
643
  return false;
644
  }
645
 
@@ -652,7 +654,7 @@ class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
652
  if ( isset( $this->_connections[$dbhname] ) ) {
653
  $dbh = $this->_connections[$dbhname]['dbh'];
654
  if ( is_resource( $dbh ) )
655
- mysql_close( $dbh );
656
 
657
  unset( $this->_connections[$dbhname] );
658
  }
@@ -779,18 +781,19 @@ class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
779
  || !defined( 'DB_NAME' ) )
780
  return $this->wpdb_mixin->bail( "We were unable to query because there was no database defined." );
781
 
782
- $connect_function = $this->persistent ? 'mysql_pconnect' : 'mysql_connect';
783
- $this->wpdb_mixin->dbh = @ $connect_function( DB_HOST, DB_USER, DB_PASSWORD, true );
 
784
 
785
  if ( !is_resource( $this->wpdb_mixin->dbh ) )
786
  return $this->wpdb_mixin->bail( "We were unable to connect to the database. (DB_HOST)" );
787
- if ( !mysql_select_db( DB_NAME, $this->wpdb_mixin->dbh ) )
788
  return $this->wpdb_mixin->bail( "We were unable to select the database." );
789
  if ( !empty( $this->wpdb_mixin->charset ) ) {
790
  $collation_query = "SET NAMES '$this->wpdb_mixin->charset'";
791
  if ( !empty( $this->wpdb_mixin->collate ) )
792
  $collation_query .= " COLLATE '$this->wpdb_mixin->collate'";
793
- mysql_query( $collation_query, $this->wpdb_mixin->dbh );
794
  }
795
 
796
  return $this->wpdb_mixin->dbh;
@@ -810,4 +813,4 @@ class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
810
 
811
  public function w3tc_usage_statistics_of_request( $storage ) {
812
  }
813
- }
7
  */
8
  class Enterprise_Dbcache_WpdbInjection_Cluster extends DbCache_WpdbInjection {
9
  /**
10
+ * Whether to check with fsockopen prior to mysqli_connect.
11
  *
12
  * @var bool
13
  */
21
  var $min_tries = 3;
22
 
23
  /**
24
+ * Whether to use mysqli_connect with persistence
25
  *
26
  * @var bool
27
  */
256
  * @return resource mysql database connection
257
  */
258
  function db_connect( $query = '', $use_master = null ) {
 
259
  if ( empty( $this->_cluster_servers ) )
260
  return $this->_db_connect_fallback();
261
 
344
  // $zone, $index
345
  extract( $zone_index, EXTR_OVERWRITE );
346
 
347
+ // $host, $user, $password, $name, $read, $write, $timeout
348
  extract( $this->_cluster_servers[$dataset][$operation][$zone][$index], EXTR_OVERWRITE );
349
 
350
  // Split host:port into $host and $port
364
  }
365
 
366
  $dbh = null;
367
+ if ( is_null( $tcp_responded ) || $tcp_responded ) {
368
+ $dbh = @mysqli_connect(
369
+ ($this->persistent ? 'p:' : '') . $host . ':' . $port,
370
+ $user, $password, true);
371
+ }
372
 
373
  $elapsed = $this->wpdb_mixin->timer_stop();
374
 
375
  if ( is_resource( $dbh ) ) {
376
+ if ( mysqli_select_db( $name, $dbh ) ) {
377
  $this->_connections[$dbhname] = array(
378
  'dbh' => $dbh,
379
  'database_name' => $name );
443
  if ( !is_resource( $dbh ) )
444
  return null;
445
 
446
+ if ( !mysqli_ping( $dbh ) ) {
447
  // disconnect (ping failed)
448
  $this->_disconnect( $dbhname );
449
  return null;
455
  /**
456
  * Sets the connection's character set.
457
  *
458
+ * @param resource $dbh The resource given by mysqli_connect
459
  * @param string $charset The character set (optional)
460
  * @param string $collate The collation (optional)
461
  */
465
  if ( !isset( $collate ) )
466
  $collate = $this->wpdb_mixin->collate;
467
  if ( $this->has_cap( 'collation', $dbh ) && !empty( $charset ) ) {
468
+ if ( function_exists( 'mysqli_set_charset' ) && $this->has_cap( 'set_charset', $dbh ) ) {
469
+ mysqli_set_charset( $charset, $dbh );
470
  $this->wpdb_mixin->real_escape = true;
471
  } else {
472
  $query = $this->wpdb_mixin->prepare( 'SET NAMES %s', $charset );
473
  if ( !empty( $collate ) )
474
  $query .= $this->wpdb_mixin->prepare( ' COLLATE %s', $collate );
475
+ mysqli_query( $query, $dbh );
476
  }
477
  }
478
  }
515
  return false;
516
 
517
  $this->wpdb_mixin->timer_start();
518
+ $this->wpdb_mixin->result = mysqli_query( $query, $this->wpdb_mixin->dbh );
519
  $elapsed = $this->wpdb_mixin->timer_stop();
520
  ++$this->wpdb_mixin->num_queries;
521
 
522
  if ( preg_match( '/^\s*SELECT\s+SQL_CALC_FOUND_ROWS\s/i', $query ) ) {
523
  if ( false === strpos( $query, "NO_SELECT_FOUND_ROWS" ) ) {
524
  $this->wpdb_mixin->timer_start();
525
+ $this->wpdb_mixin->_last_found_rows_result = mysqli_query( "SELECT FOUND_ROWS()", $this->wpdb_mixin->dbh );
526
  $elapsed += $this->wpdb_mixin->timer_stop();
527
  ++$this->wpdb_mixin->num_queries;
528
  $query .= "; SELECT FOUND_ROWS()";
536
  apply_filters( 'after_query', $query );
537
 
538
  // If there is an error then take note of it
539
+ if ( $this->wpdb_mixin->last_error = mysqli_error( $this->wpdb_mixin->dbh ) ) {
540
  $this->wpdb_mixin->print_error( $this->wpdb_mixin->last_error );
541
  return false;
542
  }
543
 
544
  if ( preg_match( "/^\\s*(insert|delete|update|replace|alter) /i", $query ) ) {
545
+ $this->wpdb_mixin->rows_affected = mysqli_affected_rows( $this->wpdb_mixin->dbh );
546
 
547
  // Take note of the insert_id
548
  if ( preg_match( "/^\\s*(insert|replace) /i", $query ) ) {
549
+ $this->wpdb_mixin->insert_id = mysqli_insert_id( $this->wpdb_mixin->dbh );
550
  }
551
  // Return number of rows affected
552
  return $this->wpdb_mixin->rows_affected;
554
  $i = 0;
555
  $this->wpdb_mixin->col_info = array();
556
  $col_info = array();
557
+ while ( $i < @mysqli_num_fields( $this->wpdb_mixin->result ) ) {
558
+ $col_info[$i] = @mysqli_fetch_field( $this->wpdb_mixin->result );
559
  $i++;
560
  }
561
  $this->wpdb_mixin->col_info = $col_info;
562
  $num_rows = 0;
563
  $this->wpdb_mixin->last_result = array();
564
+ while ( $row = @mysqli_fetch_object( $this->wpdb_mixin->result ) ) {
565
  $this->wpdb_mixin->last_result[$num_rows] = $row;
566
  $num_rows++;
567
  }
568
 
569
+ @mysqli_free_result( $this->wpdb_mixin->result );
570
 
571
  // Log number of rows the query returned
572
  $this->num_rows = $num_rows;
586
  function check_database_version( $dbh_or_table = false ) {
587
  global $wp_version;
588
  // Make sure the server has MySQL 4.1.2
589
+ $mysqli_version = preg_replace( '|[^0-9\.]|', '', $this->wpdb_mixin->db_version( $dbh_or_table ) );
590
+ if ( version_compare( $mysqli_version, '4.1.2', '<' ) )
591
  return new \WP_Error( 'database_version', sprintf( __( '<strong>ERROR</strong>: WordPress %s requires MySQL 4.1.2 or higher' ), $wp_version ) );
592
  }
593
 
641
  $dbh = $this->db_connect( "SELECT FROM $dbh_or_table $this->wpdb_mixin->users" );
642
 
643
  if ( $dbh )
644
+ return preg_replace( '/[^0-9.].*/', '', mysqli_get_server_info( $dbh ) );
645
  return false;
646
  }
647
 
654
  if ( isset( $this->_connections[$dbhname] ) ) {
655
  $dbh = $this->_connections[$dbhname]['dbh'];
656
  if ( is_resource( $dbh ) )
657
+ mysqli_close( $dbh );
658
 
659
  unset( $this->_connections[$dbhname] );
660
  }
781
  || !defined( 'DB_NAME' ) )
782
  return $this->wpdb_mixin->bail( "We were unable to query because there was no database defined." );
783
 
784
+ $this->wpdb_mixin->dbh = @mysqli_connect(
785
+ ( $this->persistent? 'p:': '' ) . DB_HOST, DB_USER, DB_PASSWORD,
786
+ true );
787
 
788
  if ( !is_resource( $this->wpdb_mixin->dbh ) )
789
  return $this->wpdb_mixin->bail( "We were unable to connect to the database. (DB_HOST)" );
790
+ if ( !mysqli_select_db( DB_NAME, $this->wpdb_mixin->dbh ) )
791
  return $this->wpdb_mixin->bail( "We were unable to select the database." );
792
  if ( !empty( $this->wpdb_mixin->charset ) ) {
793
  $collation_query = "SET NAMES '$this->wpdb_mixin->charset'";
794
  if ( !empty( $this->wpdb_mixin->collate ) )
795
  $collation_query .= " COLLATE '$this->wpdb_mixin->collate'";
796
+ mysqli_query( $collation_query, $this->wpdb_mixin->dbh );
797
  }
798
 
799
  return $this->wpdb_mixin->dbh;
813
 
814
  public function w3tc_usage_statistics_of_request( $storage ) {
815
  }
816
+ }
Enterprise_SnsServer.php CHANGED
@@ -53,6 +53,8 @@ class Enterprise_SnsServer extends Enterprise_SnsBase {
53
  */
54
  private function _subscription_confirmation( $message ) {
55
  $this->_log( 'Issuing confirm_subscription' );
 
 
56
  $response = $this->_get_api()->confirm_subscription(
57
  $topic_arn, $message->get( 'Token' ) );
58
  $this->_log( 'Subscription confirmed: ' .
@@ -125,6 +127,8 @@ class Enterprise_SnsServer extends Enterprise_SnsBase {
125
  isset( $m['extras'] ) ? $m['extras'] : null );
126
  elseif ( $action == 'flush_post' )
127
  $executor->flush_post( $m['post_id'] );
 
 
128
  elseif ( $action == 'flush_url' )
129
  $executor->flush_url( $m['url'] );
130
  elseif ( $action == 'prime_post' )
@@ -132,6 +136,8 @@ class Enterprise_SnsServer extends Enterprise_SnsBase {
132
  else
133
  throw new \Exception( 'Unknown action ' . $action );
134
 
 
 
135
  $this->_log( 'succeeded' );
136
  }
137
  }
53
  */
54
  private function _subscription_confirmation( $message ) {
55
  $this->_log( 'Issuing confirm_subscription' );
56
+ $topic_arn = $this->_config->get_string( 'cluster.messagebus.sns.topic_arn' );
57
+
58
  $response = $this->_get_api()->confirm_subscription(
59
  $topic_arn, $message->get( 'Token' ) );
60
  $this->_log( 'Subscription confirmed: ' .
127
  isset( $m['extras'] ) ? $m['extras'] : null );
128
  elseif ( $action == 'flush_post' )
129
  $executor->flush_post( $m['post_id'] );
130
+ elseif ( $action == 'flush_posts' )
131
+ $executor->flush_posts();
132
  elseif ( $action == 'flush_url' )
133
  $executor->flush_url( $m['url'] );
134
  elseif ( $action == 'prime_post' )
136
  else
137
  throw new \Exception( 'Unknown action ' . $action );
138
 
139
+ $executor->execute_delayed_operations();
140
+
141
  $this->_log( 'succeeded' );
142
  }
143
  }
Extension_CloudFlare_Plugin.php CHANGED
@@ -190,7 +190,7 @@ class Extension_CloudFlare_Plugin {
190
  break;
191
  }
192
  }
193
- } else {
194
  $ip6_ranges = $this->_config->get_array( array(
195
  'cloudflare', 'ips.ip6' ) );
196
  $ip6 = $this->get_ipv6_full( $_SERVER["REMOTE_ADDR"] );
@@ -317,11 +317,17 @@ class Extension_CloudFlare_Plugin {
317
  */
318
  private function get_ipv6_full( $ip ) {
319
  $pieces = explode( "/", $ip, 2 );
 
 
 
320
  $left_piece = $pieces[0];
321
  $right_piece = $pieces[1];
322
 
323
  // Extract out the main IP pieces
324
  $ip_pieces = explode( "::", $left_piece, 2 );
 
 
 
325
  $main_ip_piece = $ip_pieces[0];
326
  $last_ip_piece = $ip_pieces[1];
327
 
190
  break;
191
  }
192
  }
193
+ } elseif ( !empty( $_SERVER["REMOTE_ADDR"] ) ) {
194
  $ip6_ranges = $this->_config->get_array( array(
195
  'cloudflare', 'ips.ip6' ) );
196
  $ip6 = $this->get_ipv6_full( $_SERVER["REMOTE_ADDR"] );
317
  */
318
  private function get_ipv6_full( $ip ) {
319
  $pieces = explode( "/", $ip, 2 );
320
+ if ( count( $pieces ) < 2 )
321
+ return 0;
322
+
323
  $left_piece = $pieces[0];
324
  $right_piece = $pieces[1];
325
 
326
  // Extract out the main IP pieces
327
  $ip_pieces = explode( "::", $left_piece, 2 );
328
+ if ( count( $ip_pieces ) < 2 )
329
+ return 0;
330
+
331
  $main_ip_piece = $ip_pieces[0];
332
  $last_ip_piece = $ip_pieces[1];
333
 
Extension_CloudFlare_Plugin_Admin.php CHANGED
@@ -8,7 +8,8 @@ class Extension_CloudFlare_Plugin_Admin {
8
 
9
 
10
  static public function w3tc_extensions( $extensions, $config ) {
11
- global $current_user;
 
12
  $message = array();
13
  $message[] = 'CloudFlare';
14
  $cloudflare_signup_email = '';
8
 
9
 
10
  static public function w3tc_extensions( $extensions, $config ) {
11
+ $current_user = wp_get_current_user();
12
+
13
  $message = array();
14
  $message[] = 'CloudFlare';
15
  $cloudflare_signup_email = '';
Extension_FragmentCache_Plugin_Admin.php CHANGED
@@ -148,16 +148,16 @@ class Extension_FragmentCache_Plugin_Admin {
148
  if ( $c->get_string( array( 'fragmentcache', 'engine' ) ) == 'memcached' ) {
149
  $summary['memcached_servers']['fragmentcache'] = array(
150
  'servers' => $c->get_array( array( 'fragmentcache', 'memcached.servers' ) ),
151
- 'username' => $c->get_boolean( array( 'fragmentcache', 'memcached.username' ) ),
152
- 'password' => $c->get_boolean( array( 'fragmentcache', 'memcached.password' ) ),
153
  'name' => __( 'Fragment Cache', 'w3-total-cache' )
154
  );
155
  } elseif ( $c->get_string( array( 'fragmentcache', 'engine' ) ) == 'redis' ) {
156
  $summary['redis_servers']['fragmentcache'] = array(
157
  'servers' => $c->get_array( array( 'fragmentcache', 'redis.servers' ) ),
158
  'username' => $c->get_boolean( array( 'fragmentcache', 'redis.username' ) ),
159
- 'dbid' => $c->get_boolean( array( 'fragmentcache', 'redis.dbid' ) ),
160
- 'password' => $c->get_boolean( array( 'fragmentcache', 'redis.password' ) ),
161
  'name' => __( 'Fragment Cache', 'w3-total-cache' )
162
  );
163
  }
148
  if ( $c->get_string( array( 'fragmentcache', 'engine' ) ) == 'memcached' ) {
149
  $summary['memcached_servers']['fragmentcache'] = array(
150
  'servers' => $c->get_array( array( 'fragmentcache', 'memcached.servers' ) ),
151
+ 'username' => $c->get_string( array( 'fragmentcache', 'memcached.username' ) ),
152
+ 'password' => $c->get_string( array( 'fragmentcache', 'memcached.password' ) ),
153
  'name' => __( 'Fragment Cache', 'w3-total-cache' )
154
  );
155
  } elseif ( $c->get_string( array( 'fragmentcache', 'engine' ) ) == 'redis' ) {
156
  $summary['redis_servers']['fragmentcache'] = array(
157
  'servers' => $c->get_array( array( 'fragmentcache', 'redis.servers' ) ),
158
  'username' => $c->get_boolean( array( 'fragmentcache', 'redis.username' ) ),
159
+ 'dbid' => $c->get_integer( array( 'fragmentcache', 'redis.dbid' ) ),
160
+ 'password' => $c->get_string( array( 'fragmentcache', 'redis.password' ) ),
161
  'name' => __( 'Fragment Cache', 'w3-total-cache' )
162
  );
163
  }
Extension_FragmentCache_WpObjectCache.php CHANGED
@@ -520,8 +520,8 @@ class Extension_FragmentCache_WpObjectCache {
520
  'servers' => $this->_config->get_array( array( 'fragmentcache', 'memcached.servers' ) ),
521
  'persistent' => $this->_config->get_boolean( array( 'fragmentcache', 'memcached.persistent' ) ),
522
  'aws_autodiscovery' => $this->_config->get_boolean( array( 'fragmentcache', 'memcached.aws_autodiscovery' ) ),
523
- 'username' => $this->_config->get_boolean( array( 'fragmentcache', 'memcached.username' ) ),
524
- 'password' => $this->_config->get_boolean( array( 'fragmentcache', 'memcached.password' ) )
525
  );
526
  break;
527
 
@@ -529,8 +529,8 @@ class Extension_FragmentCache_WpObjectCache {
529
  $engineConfig = array(
530
  'servers' => $this->_config->get_array( array( 'fragmentcache', 'redis.servers' ) ),
531
  'persistent' => $this->_config->get_boolean( array( 'fragmentcache', 'redis.persistent' ) ),
532
- 'dbid' => $this->_config->get_boolean( array( 'fragmentcache', 'redis.dbid' ) ),
533
- 'password' => $this->_config->get_boolean( array( 'fragmentcache', 'redis.password' ) )
534
  );
535
  break;
536
 
520
  'servers' => $this->_config->get_array( array( 'fragmentcache', 'memcached.servers' ) ),
521
  'persistent' => $this->_config->get_boolean( array( 'fragmentcache', 'memcached.persistent' ) ),
522
  'aws_autodiscovery' => $this->_config->get_boolean( array( 'fragmentcache', 'memcached.aws_autodiscovery' ) ),
523
+ 'username' => $this->_config->get_string( array( 'fragmentcache', 'memcached.username' ) ),
524
+ 'password' => $this->_config->get_string( array( 'fragmentcache', 'memcached.password' ) )
525
  );
526
  break;
527
 
529
  $engineConfig = array(
530
  'servers' => $this->_config->get_array( array( 'fragmentcache', 'redis.servers' ) ),
531
  'persistent' => $this->_config->get_boolean( array( 'fragmentcache', 'redis.persistent' ) ),
532
+ 'dbid' => $this->_config->get_integer( array( 'fragmentcache', 'redis.dbid' ) ),
533
+ 'password' => $this->_config->get_string( array( 'fragmentcache', 'redis.password' ) )
534
  );
535
  break;
536
 
Extension_Genesis_Plugin.php CHANGED
@@ -212,6 +212,7 @@ class Extension_Genesis_Plugin {
212
 
213
  foreach ( $reject_uri as $expr ) {
214
  $expr = trim( $expr );
 
215
  if ( $expr != '' && preg_match( '~' . $expr . '~i', $this->_request_uri ) ) {
216
  return true;
217
  }
212
 
213
  foreach ( $reject_uri as $expr ) {
214
  $expr = trim( $expr );
215
+ $expr = str_replace( '~', '\~', $expr );
216
  if ( $expr != '' && preg_match( '~' . $expr . '~i', $this->_request_uri ) ) {
217
  return true;
218
  }
Extension_NewRelic_Plugin.php CHANGED
@@ -143,7 +143,7 @@ class Extension_NewRelic_Plugin {
143
  * @return boolean
144
  */
145
  private function _check_logged_in_role_not_allowed() {
146
- global $current_user;
147
 
148
  if ( !is_user_logged_in() )
149
  return false;
143
  * @return boolean
144
  */
145
  private function _check_logged_in_role_not_allowed() {
146
+ $current_user = wp_get_current_user();
147
 
148
  if ( !is_user_logged_in() )
149
  return false;
Extensions_Plugin_Admin.php CHANGED
@@ -124,7 +124,7 @@ class Extensions_Plugin_Admin {
124
  $s = get_option( 'w3tc_extensions_hooks' );
125
  $hooks = @json_decode( $s, true );
126
  if ( !isset( $hooks['next_check_date'] ) ||
127
- $hooks['next_check_date'] < time() || true ) {
128
  $hooks = array(
129
  'actions' => array(),
130
  'filters' => array(),
124
  $s = get_option( 'w3tc_extensions_hooks' );
125
  $hooks = @json_decode( $s, true );
126
  if ( !isset( $hooks['next_check_date'] ) ||
127
+ $hooks['next_check_date'] < time() ) {
128
  $hooks = array(
129
  'actions' => array(),
130
  'filters' => array(),
Generic_AdminActions_Flush.php CHANGED
@@ -102,9 +102,7 @@ class Generic_AdminActions_Flush {
102
  * @return void
103
  */
104
  function w3tc_flush_pgcache() {
105
- $pgcacheflush = Dispatcher::component( 'PgCache_Flush' );
106
- $pgcacheflush->flush();
107
- $pgcacheflush->flush_post_cleanup();
108
 
109
  $state_note = Dispatcher::config_state_note();
110
  $state_note->set( 'common.show_note.flush_posts_needed', false );
@@ -247,7 +245,9 @@ class Generic_AdminActions_Flush {
247
  $state_note->set( 'common.show_note.flush_posts_needed', false );
248
  $state_note->set( 'common.show_note.plugins_updated', false );
249
 
250
- $this->flush_pgcache();
 
 
251
  }
252
 
253
  if ( $this->_config->get_string( 'dbcache.engine' ) == $type && $this->_config->get_boolean( 'dbcache.enabled' ) ) {
102
  * @return void
103
  */
104
  function w3tc_flush_pgcache() {
105
+ w3tc_flush_posts();
 
 
106
 
107
  $state_note = Dispatcher::config_state_note();
108
  $state_note->set( 'common.show_note.flush_posts_needed', false );
245
  $state_note->set( 'common.show_note.flush_posts_needed', false );
246
  $state_note->set( 'common.show_note.plugins_updated', false );
247
 
248
+ $pgcacheflush = Dispatcher::component( 'PgCache_Flush' );
249
+ $pgcacheflush->flush();
250
+ $pgcacheflush->flush_post_cleanup();
251
  }
252
 
253
  if ( $this->_config->get_string( 'dbcache.engine' ) == $type && $this->_config->get_boolean( 'dbcache.enabled' ) ) {
Generic_AdminActions_Test.php CHANGED
@@ -105,32 +105,32 @@ class Generic_AdminActions_Test {
105
  if ( empty( $error ) ) {
106
  switch ( $engine ) {
107
  case 'yuijs':
108
- Minify_YUICompressor::$tempDir = Util_File::create_tmp_dir();
109
- Minify_YUICompressor::$javaExecutable = $path_java;
110
- Minify_YUICompressor::$jarFile = $path_jar;
111
 
112
- $result = Minify_YUICompressor::testJs( $error );
113
  break;
114
 
115
  case 'yuicss':
116
- Minify_YUICompressor::$tempDir = Util_File::create_tmp_dir();
117
- Minify_YUICompressor::$javaExecutable = $path_java;
118
- Minify_YUICompressor::$jarFile = $path_jar;
119
 
120
- $result = Minify_YUICompressor::testCss( $error );
121
  break;
122
 
123
  case 'ccjs':
124
- Minify_ClosureCompiler::$tempDir = Util_File::create_tmp_dir();
125
- Minify_ClosureCompiler::$javaExecutable = $path_java;
126
- Minify_ClosureCompiler::$jarFile = $path_jar;
127
 
128
- $result = Minify_ClosureCompiler::test( $error );
129
  break;
130
 
131
  case 'googleccjs':
132
 
133
- $result = Minify_JS_ClosureCompiler::test( $error );
134
  break;
135
 
136
  default:
105
  if ( empty( $error ) ) {
106
  switch ( $engine ) {
107
  case 'yuijs':
108
+ \Minify_YUICompressor::$tempDir = Util_File::create_tmp_dir();
109
+ \Minify_YUICompressor::$javaExecutable = $path_java;
110
+ \Minify_YUICompressor::$jarFile = $path_jar;
111
 
112
+ $result = \Minify_YUICompressor::testJs( $error );
113
  break;
114
 
115
  case 'yuicss':
116
+ \Minify_YUICompressor::$tempDir = Util_File::create_tmp_dir();
117
+ \Minify_YUICompressor::$javaExecutable = $path_java;
118
+ \Minify_YUICompressor::$jarFile = $path_jar;
119
 
120
+ $result = \Minify_YUICompressor::testCss( $error );
121
  break;
122
 
123
  case 'ccjs':
124
+ \Minify_ClosureCompiler::$tempDir = Util_File::create_tmp_dir();
125
+ \Minify_ClosureCompiler::$javaExecutable = $path_java;
126
+ \Minify_ClosureCompiler::$jarFile = $path_jar;
127
 
128
+ $result = \Minify_ClosureCompiler::test( $error );
129
  break;
130
 
131
  case 'googleccjs':
132
 
133
+ $result = \Minify_JS_ClosureCompiler::test( $error );
134
  break;
135
 
136
  default:
Generic_ConfigLabels.php CHANGED
@@ -9,7 +9,7 @@ class Generic_ConfigLabels {
9
  'cluster.messagebus.sns.api_key' => __( '<acronym title="Application Programming Interface">API</acronym> key:', 'w3-total-cache' ),
10
  'cluster.messagebus.sns.api_secret' => __( '<acronym title="Application Programming Interface">API</acronym> secret:', 'w3-total-cache' ),
11
  'cluster.messagebus.sns.topic_arn' => __( 'Topic <acronym title="Identification">ID</acronym>:', 'w3-total-cache' ),
12
- 'cluster.messagebus.debug' => __( 'Amazon <acronym title="Simple Notification Service">SNS</acronym>', 'w3-total-cache' ),
13
  'widget.pagespeed.key' => __( 'Page Speed <acronym title="Application Programming Interface">API</acronym> Key:', 'w3-total-cache' ),
14
  'common.force_master' => __( 'Use single network configuration file for all sites.', 'w3-total-cache' ),
15
  'config.path' => __( 'Nginx server configuration file path', 'w3-total-cache' ),
9
  'cluster.messagebus.sns.api_key' => __( '<acronym title="Application Programming Interface">API</acronym> key:', 'w3-total-cache' ),
10
  'cluster.messagebus.sns.api_secret' => __( '<acronym title="Application Programming Interface">API</acronym> secret:', 'w3-total-cache' ),
11
  'cluster.messagebus.sns.topic_arn' => __( 'Topic <acronym title="Identification">ID</acronym>:', 'w3-total-cache' ),
12
+ 'cluster.messagebus.debug' => __( 'Message Bus', 'w3-total-cache' ),
13
  'widget.pagespeed.key' => __( 'Page Speed <acronym title="Application Programming Interface">API</acronym> Key:', 'w3-total-cache' ),
14
  'common.force_master' => __( 'Use single network configuration file for all sites.', 'w3-total-cache' ),
15
  'config.path' => __( 'Nginx server configuration file path', 'w3-total-cache' ),
Generic_Environment.php CHANGED
@@ -22,7 +22,20 @@ class Generic_Environment {
22
  $this->add_index_to_folders();
23
 
24
  if ( count( $exs->exceptions() ) <= 0 ) {
25
- $this->notify_no_config_present( $config, $exs );
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  }
27
 
28
  if ( count( $exs->exceptions() ) > 0 )
@@ -172,11 +185,6 @@ class Generic_Environment {
172
  * @param Util_Environment_Exceptions $exs
173
  */
174
  private function notify_no_config_present( $config, $exs ) {
175
- if ( ( file_exists( Config::util_config_filename( 0, false ) ) ||
176
- file_exists( Config::util_config_filename_legacy( 0, false ) ) )
177
- && $config->get_integer( 'common.instance_id', 0 ) != 0 )
178
- return;
179
-
180
  $onclick = 'document.location.href=\'' .
181
  addslashes( wp_nonce_url(
182
  'admin.php?page=w3tc_general&w3tc_save_options', 'w3tc' ) ) .
22
  $this->add_index_to_folders();
23
 
24
  if ( count( $exs->exceptions() ) <= 0 ) {
25
+ $f = file_exists( Config::util_config_filename( 0, false ) );
26
+ $f2 = file_exists( Config::util_config_filename_legacy_v2( 0, false ) );
27
+
28
+ $c = Dispatcher::config_master();
29
+ if ( ( $f || $f2 ) && $c->is_compiled() ) {
30
+ $c->save();
31
+ $f = file_exists( Config::util_config_filename( 0, false ) );
32
+ }
33
+
34
+ if ( $f && $f2 )
35
+ @unlink( Config::util_config_filename_legacy_v2( 0, false ) );
36
+
37
+ if ( !$f && !$f2 && $config->get_integer( 'common.instance_id', 0 ) == 0 )
38
+ $this->notify_no_config_present( $config, $exs );
39
  }
40
 
41
  if ( count( $exs->exceptions() ) > 0 )
185
  * @param Util_Environment_Exceptions $exs
186
  */
187
  private function notify_no_config_present( $config, $exs ) {
 
 
 
 
 
188
  $onclick = 'document.location.href=\'' .
189
  addslashes( wp_nonce_url(
190
  'admin.php?page=w3tc_general&w3tc_save_options', 'w3tc' ) ) .
Generic_Page_Dashboard.php CHANGED
@@ -24,7 +24,7 @@ class Generic_Page_Dashboard extends Base_Page_Settings {
24
  function view() {
25
  $module_status = Dispatcher::component( 'ModuleStatus' );
26
  Util_Widget::setup();
27
- global $current_user;
28
  $config_master = $this->_config_master;
29
 
30
  $browsercache_enabled = $module_status->is_enabled( 'browsercache' );
24
  function view() {
25
  $module_status = Dispatcher::component( 'ModuleStatus' );
26
  Util_Widget::setup();
27
+ $current_user = wp_get_current_user();
28
  $config_master = $this->_config_master;
29
 
30
  $browsercache_enabled = $module_status->is_enabled( 'browsercache' );
Generic_Page_General.php CHANGED
@@ -18,7 +18,7 @@ class Generic_Page_General extends Base_Page_Settings {
18
  */
19
  function view() {
20
 
21
- global $current_user;
22
  $config_master = $this->_config_master;
23
  /**
24
  *
18
  */
19
  function view() {
20
 
21
+ $current_user = wp_get_current_user();
22
  $config_master = $this->_config_master;
23
  /**
24
  *
Generic_Plugin.php CHANGED
@@ -508,8 +508,10 @@ class Generic_Plugin {
508
 
509
  $buffer .= sprintf( "\r\n Served from: %s @ %s by W3 Total Cache -->", Util_Content::escape_comment( $host ), $date );
510
  }
511
- }
512
 
 
 
 
513
  $buffer = Util_Bus::do_ob_callbacks(
514
  array( 'minify', 'newrelic', 'cdn', 'browsercache', 'pagecache' ),
515
  $buffer );
@@ -529,13 +531,6 @@ class Generic_Plugin {
529
  return false;
530
  }
531
 
532
- /**
533
- * Skip if admin
534
- */
535
- if ( defined( 'WP_ADMIN' ) ) {
536
- return false;
537
- }
538
-
539
  /**
540
  * Skip if doing AJAX
541
  */
@@ -588,7 +583,7 @@ class Generic_Plugin {
588
  * If so, set a role cookie so the requests wont be cached
589
  */
590
  function check_login_action( $logged_in_cookie = false, $expire = ' ', $expiration = 0, $user_id = 0, $action = 'logged_out' ) {
591
- global $current_user;
592
  if ( isset( $current_user->ID ) && !$current_user->ID )
593
  $user_id = new \WP_User( $user_id );
594
  else
508
 
509
  $buffer .= sprintf( "\r\n Served from: %s @ %s by W3 Total Cache -->", Util_Content::escape_comment( $host ), $date );
510
  }
 
511
 
512
+ $buffer = apply_filters( 'w3tc_process_content', $buffer );
513
+ }
514
+
515
  $buffer = Util_Bus::do_ob_callbacks(
516
  array( 'minify', 'newrelic', 'cdn', 'browsercache', 'pagecache' ),
517
  $buffer );
531
  return false;
532
  }
533
 
 
 
 
 
 
 
 
534
  /**
535
  * Skip if doing AJAX
536
  */
583
  * If so, set a role cookie so the requests wont be cached
584
  */
585
  function check_login_action( $logged_in_cookie = false, $expire = ' ', $expiration = 0, $user_id = 0, $action = 'logged_out' ) {
586
+ $current_user = wp_get_current_user();
587
  if ( isset( $current_user->ID ) && !$current_user->ID )
588
  $user_id = new \WP_User( $user_id );
589
  else
Generic_Plugin_Admin.php CHANGED
@@ -172,7 +172,7 @@ class Generic_Plugin_Admin {
172
  wp_nonce_ays( 'w3tc' );
173
 
174
  try {
175
- $base_capability = apply_filters( 'w3tc_ajax', 'manage_options' );
176
  $capability = apply_filters( 'w3tc_ajax_capability_' . $_REQUEST['w3tc_action'],
177
  $base_capability );
178
  if ( !empty( $capability ) && !current_user_can( $capability ) )
@@ -362,7 +362,8 @@ class Generic_Plugin_Admin {
362
  add_action( 'admin_print_styles', array( $this, 'print_plugins_page_css' ) );
363
  }
364
 
365
- if ( $this->is_w3tc_page ) {
 
366
  /**
367
  * Only admin can see W3TC notices and errors
368
  */
@@ -508,7 +509,7 @@ class Generic_Plugin_Admin {
508
  array_unshift( $links,
509
  '<a class="edit" href="admin.php?page=w3tc_general">Settings</a>' );
510
  array_unshift( $links,
511
- '<a class="delete" href="admin.php?page=w3tc_support">Premium Support</a>' );
512
 
513
 
514
  if ( !is_writable( WP_CONTENT_DIR ) ||
@@ -703,15 +704,12 @@ class Generic_Plugin_Admin {
703
  * Filesystem environment fix, if needed
704
  */
705
  try {
706
- global $pagenow;
707
- if ( $pagenow == 'plugins.php' || Util_Admin::is_w3tc_admin_page() ) {
708
- $environment = Dispatcher::component( 'Root_Environment' );
709
- $environment->fix_in_wpadmin( $this->_config );
710
 
711
- if ( isset( $_REQUEST['upgrade'] ) )
712
- $notes[] = __( 'Required files and directories have been automatically created',
713
- 'w3-total-cache' );
714
- }
715
  } catch ( Util_Environment_Exceptions $exs ) {
716
  $r = Util_Activation::parse_environment_exceptions( $exs );
717
  $n = 1;
@@ -773,22 +771,24 @@ class Generic_Plugin_Admin {
773
  }
774
  }
775
 
776
- $errors = apply_filters( 'w3tc_errors', $errors );
777
- $notes = apply_filters( 'w3tc_notes', $notes );
778
-
779
- /**
780
- * Show messages
781
- */
782
- foreach ( $notes as $key => $note ) {
783
- echo sprintf(
784
- '<div class="updated w3tc_note" id="%s"><p>%s</p></div>',
785
- $key,
786
- $note );
787
- }
788
 
789
- foreach ( $errors as $key => $error ) {
790
- echo sprintf( '<div class="error w3tc_error" id="%s"><p>%s</p></div>',
791
- $key, $error );
 
 
 
 
 
 
 
 
 
 
 
792
  }
793
  }
794
  }
172
  wp_nonce_ays( 'w3tc' );
173
 
174
  try {
175
+ $base_capability = apply_filters( 'w3tc_ajax_base_capability_', 'manage_options' );
176
  $capability = apply_filters( 'w3tc_ajax_capability_' . $_REQUEST['w3tc_action'],
177
  $base_capability );
178
  if ( !empty( $capability ) && !current_user_can( $capability ) )
362
  add_action( 'admin_print_styles', array( $this, 'print_plugins_page_css' ) );
363
  }
364
 
365
+ global $pagenow;
366
+ if ( $pagenow == 'plugins.php' || $this->is_w3tc_page ) {
367
  /**
368
  * Only admin can see W3TC notices and errors
369
  */
509
  array_unshift( $links,
510
  '<a class="edit" href="admin.php?page=w3tc_general">Settings</a>' );
511
  array_unshift( $links,
512
+ '<a class="edit" style="color: red" href="admin.php?page=w3tc_support">Premium Support</a>' );
513
 
514
 
515
  if ( !is_writable( WP_CONTENT_DIR ) ||
704
  * Filesystem environment fix, if needed
705
  */
706
  try {
707
+ $environment = Dispatcher::component( 'Root_Environment' );
708
+ $environment->fix_in_wpadmin( $this->_config );
 
 
709
 
710
+ if ( isset( $_REQUEST['upgrade'] ) )
711
+ $notes[] = __( 'Required files and directories have been automatically created',
712
+ 'w3-total-cache' );
 
713
  } catch ( Util_Environment_Exceptions $exs ) {
714
  $r = Util_Activation::parse_environment_exceptions( $exs );
715
  $n = 1;
771
  }
772
  }
773
 
774
+ if ( Util_Admin::is_w3tc_admin_page() ) {
775
+ $errors = apply_filters( 'w3tc_errors', $errors );
776
+ $notes = apply_filters( 'w3tc_notes', $notes );
 
 
 
 
 
 
 
 
 
777
 
778
+ /**
779
+ * Show messages
780
+ */
781
+ foreach ( $notes as $key => $note ) {
782
+ echo sprintf(
783
+ '<div class="updated w3tc_note" id="%s"><p>%s</p></div>',
784
+ $key,
785
+ $note );
786
+ }
787
+
788
+ foreach ( $errors as $key => $error ) {
789
+ echo sprintf( '<div class="error w3tc_error" id="%s"><p>%s</p></div>',
790
+ $key, $error );
791
+ }
792
  }
793
  }
794
  }
Generic_Plugin_AdminNotifications.php CHANGED
@@ -109,7 +109,7 @@ class Generic_Plugin_AdminNotifications {
109
 
110
  public function w3tc_ajax_generic_support_us() {
111
  $supports = $this->get_supports();
112
- global $current_user;
113
  wp_get_current_user();
114
  $email = $current_user->user_email;
115
  include W3TC_INC_DIR . '/lightbox/support_us.php';
109
 
110
  public function w3tc_ajax_generic_support_us() {
111
  $supports = $this->get_supports();
112
+ $current_user = wp_get_current_user();
113
  wp_get_current_user();
114
  $email = $current_user->user_email;
115
  include W3TC_INC_DIR . '/lightbox/support_us.php';
Minify_ConfigLabels.php CHANGED
@@ -35,7 +35,7 @@ class Minify_ConfigLabels {
35
  'minify.reject.files.js' => __( 'Never minify the following <acronym title="JavaScript">JS</acronym> files:', 'w3-total-cache' ),
36
  'minify.reject.files.css' => __( 'Never minify the following <acronym title="Cascading Style Sheet">CSS</acronym> files:', 'w3-total-cache' ),
37
  'minify.reject.ua' => __( 'Rejected user agents:', 'w3-total-cache' ),
38
- 'minify.cache.files' => __( 'Include external files/libaries:', 'w3-total-cache' ),
39
  // options->minify->ccjs
40
  'minify.ccjs.options.formatting' => __( 'Pretty print', 'w3-total-cache' ),
41
  // options->minify->ccjs2
35
  'minify.reject.files.js' => __( 'Never minify the following <acronym title="JavaScript">JS</acronym> files:', 'w3-total-cache' ),
36
  'minify.reject.files.css' => __( 'Never minify the following <acronym title="Cascading Style Sheet">CSS</acronym> files:', 'w3-total-cache' ),
37
  'minify.reject.ua' => __( 'Rejected user agents:', 'w3-total-cache' ),
38
+ 'minify.cache.files' => __( 'Include external files/libraries:', 'w3-total-cache' ),
39
  // options->minify->ccjs
40
  'minify.ccjs.options.formatting' => __( 'Pretty print', 'w3-total-cache' ),
41
  // options->minify->ccjs2
Minify_ContentMinifier.php CHANGED
@@ -115,21 +115,21 @@ class Minify_ContentMinifier {
115
  function init( $engine ) {
116
  switch ( $engine ) {
117
  case 'yuijs':
118
- Minify_YUICompressor::$tempDir = Util_File::create_tmp_dir();
119
- Minify_YUICompressor::$javaExecutable = $this->_config->get_string( 'minify.yuijs.path.java' );
120
- Minify_YUICompressor::$jarFile = $this->_config->get_string( 'minify.yuijs.path.jar' );
121
  break;
122
 
123
  case 'yuicss':
124
- Minify_YUICompressor::$tempDir = Util_File::create_tmp_dir();
125
- Minify_YUICompressor::$javaExecutable = $this->_config->get_string( 'minify.yuicss.path.java' );
126
- Minify_YUICompressor::$jarFile = $this->_config->get_string( 'minify.yuicss.path.jar' );
127
  break;
128
 
129
  case 'ccjs':
130
- Minify_ClosureCompiler::$tempDir = Util_File::create_tmp_dir();
131
- Minify_ClosureCompiler::$javaExecutable = $this->_config->get_string( 'minify.ccjs.path.java' );
132
- Minify_ClosureCompiler::$jarFile = $this->_config->get_string( 'minify.ccjs.path.jar' );
133
  break;
134
  }
135
  }
115
  function init( $engine ) {
116
  switch ( $engine ) {
117
  case 'yuijs':
118
+ \Minify_YUICompressor::$tempDir = Util_File::create_tmp_dir();
119
+ \Minify_YUICompressor::$javaExecutable = $this->_config->get_string( 'minify.yuijs.path.java' );
120
+ \Minify_YUICompressor::$jarFile = $this->_config->get_string( 'minify.yuijs.path.jar' );
121
  break;
122
 
123
  case 'yuicss':
124
+ \Minify_YUICompressor::$tempDir = Util_File::create_tmp_dir();
125
+ \Minify_YUICompressor::$javaExecutable = $this->_config->get_string( 'minify.yuicss.path.java' );
126
+ \Minify_YUICompressor::$jarFile = $this->_config->get_string( 'minify.yuicss.path.jar' );
127
  break;
128
 
129
  case 'ccjs':
130
+ \Minify_ClosureCompiler::$tempDir = Util_File::create_tmp_dir();
131
+ \Minify_ClosureCompiler::$javaExecutable = $this->_config->get_string( 'minify.ccjs.path.java' );
132
+ \Minify_ClosureCompiler::$jarFile = $this->_config->get_string( 'minify.ccjs.path.jar' );
133
  break;
134
  }
135
  }
Minify_Core.php CHANGED
@@ -63,8 +63,19 @@ class Minify_Core {
63
  if ( Util_Environment::is_url( $file ) ) {
64
  $c = Dispatcher::config();
65
  $external = $c->get_array( 'minify.cache.files' );
 
 
66
  foreach ( $external as $ext ) {
67
- if ( preg_match( '#'.Util_Environment::get_url_regexp( $ext ).'#', $file ) && !$verified ) {
 
 
 
 
 
 
 
 
 
68
  $verified = true;
69
  }
70
  }
@@ -156,8 +167,8 @@ class Minify_Core {
156
  'persistent' => $c->get_boolean( 'minify.memcached.persistent' ),
157
  'aws_autodiscovery' =>
158
  $c->get_boolean( 'minify.memcached.aws_autodiscovery' ),
159
- 'username' => $c->get_boolean( 'minify.memcached.username' ),
160
- 'password' => $c->get_boolean( 'minify.memcached.password' )
161
  );
162
  break;
163
 
@@ -165,8 +176,8 @@ class Minify_Core {
165
  $engineConfig = array(
166
  'servers' => $c->get_array( 'minify.redis.servers' ),
167
  'persistent' => $c->get_boolean( 'minify.redis.persistent' ),
168
- 'dbid' => $c->get_boolean( 'minify.redis.dbid' ),
169
- 'password' => $c->get_boolean( 'minify.redis.password' )
170
  );
171
  break;
172
 
63
  if ( Util_Environment::is_url( $file ) ) {
64
  $c = Dispatcher::config();
65
  $external = $c->get_array( 'minify.cache.files' );
66
+ $external_regexp = $c->get_boolean( 'minify.cache.files_regexp' );
67
+
68
  foreach ( $external as $ext ) {
69
+ if ( empty( $ext ) )
70
+ continue;
71
+
72
+ if ( !$external_regexp &&
73
+ preg_match( '~^' . Util_Environment::get_url_regexp( $ext ) . '~', $file ) &&
74
+ !$verified ) {
75
+ $verified = true;
76
+ }
77
+ if ( $external_regexp &&
78
+ preg_match( '~' . $ext . '~', $file ) && !$verified ) {
79
  $verified = true;
80
  }
81
  }
167
  'persistent' => $c->get_boolean( 'minify.memcached.persistent' ),
168
  'aws_autodiscovery' =>
169
  $c->get_boolean( 'minify.memcached.aws_autodiscovery' ),
170
+ 'username' => $c->get_string( 'minify.memcached.username' ),
171
+ 'password' => $c->get_string( 'minify.memcached.password' )
172
  );
173
  break;
174
 
176
  $engineConfig = array(
177
  'servers' => $c->get_array( 'minify.redis.servers' ),
178
  'persistent' => $c->get_boolean( 'minify.redis.persistent' ),
179
+ 'dbid' => $c->get_integer( 'minify.redis.dbid' ),
180
+ 'password' => $c->get_string( 'minify.redis.password' )
181
  );
182
  break;
183
 
Minify_Environment.php CHANGED
@@ -40,7 +40,7 @@ class Minify_Environment {
40
  }
41
 
42
  // if no errors so far - check if rewrite actually works
43
- if ( count( $exs->exceptions() ) <= 0 || true ) {
44
  try {
45
  if ( $config->get_boolean( 'minify.enabled' ) &&
46
  $config->get_boolean( 'minify.rewrite' ) &&
@@ -224,11 +224,11 @@ class Minify_Environment {
224
  ( Util_Environment::is_nginx() ? 'nginx configuration file' : '.htaccess file' ) .
225
  ' contains rules to rewrite url ' .
226
  $url . '. If handled by ' .
227
- 'plugin, it returns "OK" message.<br/>';
228
  $tech_message .= 'The plugin made a request to ' .
229
  $url . ' but received: <br />' .
230
  $result . '<br />';
231
- $tech_message .= 'instead of "OK" response. <br />';
232
 
233
  $error = '<strong>W3 Total Cache error:</strong>It appears Minify ' .
234
  '<acronym title="Uniform Resource Locator">URL</acronym> ' .
@@ -276,7 +276,7 @@ class Minify_Environment {
276
  else
277
  $result = is_wp_error( $response ) ?
278
  $response->get_error_message() :
279
- implode( ' ', $response['response'] );
280
 
281
  set_site_transient( $key, $result, 30 );
282
  }
@@ -366,7 +366,8 @@ class Minify_Environment {
366
  * @return string
367
  */
368
  function rules_core_generate_apache( $config ) {
369
- $cache_dir = Util_Rule::filename_to_uri( W3TC_CACHE_MINIFY_DIR );
 
370
  $site_uri = rtrim( network_site_url( '', 'relative' ), '/' ) . '/';
371
 
372
  $engine = $config->get_string( 'minify.engine' );
@@ -379,16 +380,17 @@ class Minify_Environment {
379
  $rules .= W3TC_MARKER_BEGIN_MINIFY_CORE . "\n";
380
  $rules .= "<IfModule mod_rewrite.c>\n";
381
  $rules .= " RewriteEngine On\n";
382
- $rules .= " RewriteBase " . $cache_dir . "/\n";
383
 
384
  if ( $engine == 'file' ) {
385
  if ( $compression ) {
386
  $rules .= " RewriteCond %{HTTP:Accept-Encoding} gzip\n";
387
  $rules .= " RewriteRule .* - [E=APPEND_EXT:.gzip]\n";
 
 
 
 
388
  }
389
-
390
- $rules .= " RewriteCond %{REQUEST_FILENAME}%{ENV:APPEND_EXT} -" . ( $config->get_boolean( 'minify.file.nfs' ) ? 'F' : 'f' ) . "\n";
391
- $rules .= " RewriteRule (.*) $1%{ENV:APPEND_EXT} [L]\n";
392
  }
393
  $rules .= " RewriteRule ^(.+\\.(css|js))$ ${site_uri}index.php [L]\n";
394
 
@@ -405,18 +407,19 @@ class Minify_Environment {
405
  * @return string
406
  */
407
  function rules_core_generate_nginx( $config ) {
408
- $cache_dir = Util_Rule::filename_to_uri( W3TC_CACHE_MINIFY_DIR );
 
409
  $first_regex_var = '$1';
410
 
411
  // for subdir - need to count subdir in url
412
  if ( Util_Environment::is_wpmu() && !Util_Environment::is_wpmu_subdomain() ) {
413
  // take into accont case when whole subdir wpmu is installed in subdir
414
  $home_uri = network_home_url( '', 'relative' );
415
- if ( substr( $cache_dir, 0, strlen( $home_uri ) ) == $home_uri )
416
- $cache_dir = $home_uri . '([a-z0-9]+/)?' .
417
- substr( $cache_dir, strlen( $home_uri ) );
418
  else
419
- $cache_dir = '(/[a-z0-9]+)?' . $cache_dir;
420
 
421
  $first_regex_var = '$2';
422
  }
@@ -445,7 +448,7 @@ class Minify_Environment {
445
  $rules .= " rewrite (.*) $1\$w3tc_enc break;\n";
446
  $rules .= "}\n";
447
  }
448
- $rules .= "rewrite ^$cache_dir/ ${minify_uri}index.php last;\n";
449
  $rules .= W3TC_MARKER_END_MINIFY_CORE . "\n";
450
 
451
  return $rules;
@@ -537,9 +540,13 @@ class Minify_Environment {
537
 
538
  $rules = '';
539
  $rules .= W3TC_MARKER_BEGIN_MINIFY_CACHE . "\n";
 
540
  if ( $compatibility ) {
541
  $rules .= "Options -MultiViews\n";
542
- }
 
 
 
543
 
544
  if ( $etag ) {
545
  $rules .= "FileETag MTime Size\n";
@@ -643,7 +650,8 @@ class Minify_Environment {
643
  * @return string
644
  */
645
  private function rules_cache_generate_nginx( $config ) {
646
- $cache_dir = Util_Rule::filename_to_uri( W3TC_CACHE_MINIFY_DIR );
 
647
 
648
  $browsercache = $config->get_boolean( 'browsercache.enabled' );
649
  $compression = ( $browsercache && $config->get_boolean( 'browsercache.cssjs.compression' ) );
@@ -706,20 +714,20 @@ class Minify_Environment {
706
  }
707
  }
708
 
709
- $rules .= "location ~ " . $cache_dir . ".*\\.js$ {\n";
710
  $rules .= " types {}\n";
711
  $rules .= " default_type application/x-javascript;\n";
712
  $rules .= $common_rules;
713
  $rules .= "}\n";
714
 
715
- $rules .= "location ~ " . $cache_dir . ".*\\.css$ {\n";
716
  $rules .= " types {}\n";
717
  $rules .= " default_type text/css;\n";
718
  $rules .= $common_rules;
719
  $rules .= "}\n";
720
 
721
  if ( $compression ) {
722
- $rules .= "location ~ " . $cache_dir . ".*js\\.gzip$ {\n";
723
  $rules .= " gzip off;\n";
724
  $rules .= " types {}\n";
725
  $rules .= " default_type application/x-javascript;\n";
@@ -727,7 +735,7 @@ class Minify_Environment {
727
  $rules .= " add_header Content-Encoding gzip;\n";
728
  $rules .= "}\n";
729
 
730
- $rules .= "location ~ " . $cache_dir . ".*css\\.gzip$ {\n";
731
  $rules .= " gzip off;\n";
732
  $rules .= " types {}\n";
733
  $rules .= " default_type text/css;\n";
40
  }
41
 
42
  // if no errors so far - check if rewrite actually works
43
+ if ( count( $exs->exceptions() ) <= 0 ) {
44
  try {
45
  if ( $config->get_boolean( 'minify.enabled' ) &&
46
  $config->get_boolean( 'minify.rewrite' ) &&
224
  ( Util_Environment::is_nginx() ? 'nginx configuration file' : '.htaccess file' ) .
225
  ' contains rules to rewrite url ' .
226
  $url . '. If handled by ' .
227
+ 'plugin, it returns "Minify OK" message.<br/>';
228
  $tech_message .= 'The plugin made a request to ' .
229
  $url . ' but received: <br />' .
230
  $result . '<br />';
231
+ $tech_message .= 'instead of "Minify OK" response. <br />';
232
 
233
  $error = '<strong>W3 Total Cache error:</strong>It appears Minify ' .
234
  '<acronym title="Uniform Resource Locator">URL</acronym> ' .
276
  else
277
  $result = is_wp_error( $response ) ?
278
  $response->get_error_message() :
279
+ implode( ' ', $response['body'] );
280
 
281
  set_site_transient( $key, $result, 30 );
282
  }
366
  * @return string
367
  */
368
  function rules_core_generate_apache( $config ) {
369
+ $cache_uri = Util_Environment::url_to_uri(
370
+ Util_Environment::filename_to_url( W3TC_CACHE_MINIFY_DIR ) ) . '/';
371
  $site_uri = rtrim( network_site_url( '', 'relative' ), '/' ) . '/';
372
 
373
  $engine = $config->get_string( 'minify.engine' );
380
  $rules .= W3TC_MARKER_BEGIN_MINIFY_CORE . "\n";
381
  $rules .= "<IfModule mod_rewrite.c>\n";
382
  $rules .= " RewriteEngine On\n";
383
+ $rules .= " RewriteBase " . $cache_uri . "\n";
384
 
385
  if ( $engine == 'file' ) {
386
  if ( $compression ) {
387
  $rules .= " RewriteCond %{HTTP:Accept-Encoding} gzip\n";
388
  $rules .= " RewriteRule .* - [E=APPEND_EXT:.gzip]\n";
389
+ $rules .= " RewriteCond %{REQUEST_FILENAME}%{ENV:APPEND_EXT} -" . ( $config->get_boolean( 'minify.file.nfs' ) ? 'F' : 'f' ) . "\n";
390
+ $rules .= " RewriteRule (.*) $1%{ENV:APPEND_EXT} [L]\n";
391
+ } else {
392
+ $rules .= " RewriteCond %{REQUEST_FILENAME} !-f\n";
393
  }
 
 
 
394
  }
395
  $rules .= " RewriteRule ^(.+\\.(css|js))$ ${site_uri}index.php [L]\n";
396
 
407
  * @return string
408
  */
409
  function rules_core_generate_nginx( $config ) {
410
+ $cache_uri = Util_Environment::url_to_uri(
411
+ Util_Environment::filename_to_url( W3TC_CACHE_MINIFY_DIR ) ) . '/';
412
  $first_regex_var = '$1';
413
 
414
  // for subdir - need to count subdir in url
415
  if ( Util_Environment::is_wpmu() && !Util_Environment::is_wpmu_subdomain() ) {
416
  // take into accont case when whole subdir wpmu is installed in subdir
417
  $home_uri = network_home_url( '', 'relative' );
418
+ if ( substr( $cache_uri, 0, strlen( $home_uri ) ) == $home_uri )
419
+ $cache_uri = $home_uri . '([a-z0-9]+/)?' .
420
+ substr( $cache_uri, strlen( $home_uri ) );
421
  else
422
+ $cache_uri = '(/[a-z0-9]+)?' . $cache_uri;
423
 
424
  $first_regex_var = '$2';
425
  }
448
  $rules .= " rewrite (.*) $1\$w3tc_enc break;\n";
449
  $rules .= "}\n";
450
  }
451
+ $rules .= "rewrite ^$cache_uri ${minify_uri}index.php last;\n";
452
  $rules .= W3TC_MARKER_END_MINIFY_CORE . "\n";
453
 
454
  return $rules;
540
 
541
  $rules = '';
542
  $rules .= W3TC_MARKER_BEGIN_MINIFY_CACHE . "\n";
543
+ /* workaround for .gzip
544
  if ( $compatibility ) {
545
  $rules .= "Options -MultiViews\n";
546
+ }*/
547
+ $rules .= "<IfModule mod_negotiation.c>\n";
548
+ $rules .= " Options -MultiViews\n";
549
+ $rules .= "</IfModule>\n";
550
 
551
  if ( $etag ) {
552
  $rules .= "FileETag MTime Size\n";
650
  * @return string
651
  */
652
  private function rules_cache_generate_nginx( $config ) {
653
+ $cache_uri = Util_Environment::url_to_uri(
654
+ Util_Environment::filename_to_url( W3TC_CACHE_MINIFY_DIR ) ) . '/';
655
 
656
  $browsercache = $config->get_boolean( 'browsercache.enabled' );
657
  $compression = ( $browsercache && $config->get_boolean( 'browsercache.cssjs.compression' ) );
714
  }
715
  }
716
 
717
+ $rules .= "location ~ " . $cache_uri . ".*\\.js$ {\n";
718
  $rules .= " types {}\n";
719
  $rules .= " default_type application/x-javascript;\n";
720
  $rules .= $common_rules;
721
  $rules .= "}\n";
722
 
723
+ $rules .= "location ~ " . $cache_uri . ".*\\.css$ {\n";
724
  $rules .= " types {}\n";
725
  $rules .= " default_type text/css;\n";
726
  $rules .= $common_rules;
727
  $rules .= "}\n";
728
 
729
  if ( $compression ) {
730
+ $rules .= "location ~ " . $cache_uri . ".*js\\.gzip$ {\n";
731
  $rules .= " gzip off;\n";
732
  $rules .= " types {}\n";
733
  $rules .= " default_type application/x-javascript;\n";
735
  $rules .= " add_header Content-Encoding gzip;\n";
736
  $rules .= "}\n";
737
 
738
+ $rules .= "location ~ " . $cache_uri . ".*css\\.gzip$ {\n";
739
  $rules .= " gzip off;\n";
740
  $rules .= " types {}\n";
741
  $rules .= " default_type text/css;\n";
Minify_MinifiedFileRequestHandler.php CHANGED
@@ -503,8 +503,6 @@ class Minify_MinifiedFileRequestHandler {
503
  $result = array();
504
  if ( is_array( $files ) && count( $files ) > 0 ) {
505
  foreach ( $files as $file ) {
506
- $file = Util_Environment::url_to_docroot_filename( $file );
507
-
508
  if ( Util_Environment::is_url( $file ) ) {
509
  $precached_file = $this->_precache_file( $file, $type );
510
 
@@ -514,6 +512,7 @@ class Minify_MinifiedFileRequestHandler {
514
  Minify_Core::debug_error( sprintf( 'Unable to cache remote file: "%s"', $file ) );
515
  }
516
  } else {
 
517
  $path = Util_Environment::document_root() . '/' . $file;
518
 
519
  if ( file_exists( $path ) ) {
@@ -549,7 +548,7 @@ class Minify_MinifiedFileRequestHandler {
549
 
550
  $message = '<h1>W3TC Minify Error</h1>';
551
 
552
- if ( $debug ) {
553
  $message .= sprintf( '<p>%s.</p>', $error );
554
  } else {
555
  $message .= '<p>Enable debug mode to see error message.</p>';
@@ -557,7 +556,7 @@ class Minify_MinifiedFileRequestHandler {
557
 
558
  if ( $quiet ) {
559
  return array(
560
- 'content' => array( 'content' => $message )
561
  );
562
  }
563
 
@@ -586,11 +585,10 @@ class Minify_MinifiedFileRequestHandler {
586
  $cache_path = sprintf( '%s/minify_%s.%s', Util_Environment::cache_blog_dir( 'minify' ), md5( $url ), $type );
587
 
588
  if ( !file_exists( $cache_path ) || @filemtime( $cache_path ) < ( time() - $lifetime ) ) {
589
-
590
  if ( !@is_dir( dirname( $cache_path ) ) ) {
591
-
592
- Util_File::mkdir_from( dirname( $cache_path ), W3TC_CACHE_DIR );
593
  }
 
594
  Util_Http::download( $url, $cache_path );
595
  }
596
 
@@ -619,9 +617,11 @@ class Minify_MinifiedFileRequestHandler {
619
  * @return object
620
  */
621
  function _get_cache() {
622
- static $cache = array();
 
 
 
623
 
624
- if ( !isset( $cache[0] ) ) {
625
  switch ( $this->_config->get_string( 'minify.engine' ) ) {
626
  case 'memcached':
627
  $config = array(
@@ -632,16 +632,14 @@ class Minify_MinifiedFileRequestHandler {
632
  'servers' => $this->_config->get_array( 'minify.memcached.servers' ),
633
  'persistent' => $this->_config->get_boolean( 'minify.memcached.persistent' ),
634
  'aws_autodiscovery' => $this->_config->get_boolean( 'minify.memcached.aws_autodiscovery' ),
635
- 'username' => $this->_config->get_boolean( 'minify.memcached.username' ),
636
- 'password' => $this->_config->get_boolean( 'minify.memcached.password' )
637
  );
638
  if ( class_exists( 'Memcached' ) ) {
639
- $w3_cache = new Cache_Memcached( $config );
640
- } else if ( class_exists( 'Memcache' ) ) {
641
- $w3_cache = new Cache_Memcache( $config );
642
- }
643
-
644
- $cache[0] = new \Minify_Cache_W3TCDerived( $w3_cache );
645
  break;
646
 
647
  case 'redis':
@@ -652,16 +650,11 @@ class Minify_MinifiedFileRequestHandler {
652
  'module' => 'minify',
653
  'servers' => $this->_config->get_array( 'minify.redis.servers' ),
654
  'persistent' => $this->_config->get_boolean( 'minify.redis.persistent' ),
655
- 'dbid' => $this->_config->get_boolean( 'minify.redis.dbid' ),
656
- 'password' => $this->_config->get_boolean( 'minify.redis.password' )
657
  );
658
- if ( class_exists( 'Memcached' ) ) {
659
- $w3_cache = new Cache_Memcached( $config );
660
- } else if ( class_exists( 'Memcache' ) ) {
661
- $w3_cache = new Cache_Memcache( $config );
662
- }
663
 
664
- $cache[0] = new \Minify_Cache_W3TCDerived( $w3_cache );
665
  break;
666
 
667
  case 'apc':
@@ -672,12 +665,11 @@ class Minify_MinifiedFileRequestHandler {
672
  'module' => 'minify'
673
  );
674
 
675
- if ( function_exists( 'apcu_store' ) )
676
- $w3_cache = new Cache_Apcu( $config );
677
- else if ( function_exists( 'apc_store' ) )
678
- $w3_cache = new Cache_Apc( $config );
679
-
680
- $cache[0] = new \Minify_Cache_W3TCDerived( $w3_cache );
681
  break;
682
 
683
  case 'eaccelerator':
@@ -687,8 +679,7 @@ class Minify_MinifiedFileRequestHandler {
687
  'host' => Util_Environment::host(),
688
  'module' => 'minify'
689
  );
690
- $w3_cache = new Cache_Eaccelerator( $config );
691
- $cache[0] = new \Minify_Cache_W3TCDerived( $w3_cache );
692
  break;
693
 
694
  case 'xcache':
@@ -698,8 +689,7 @@ class Minify_MinifiedFileRequestHandler {
698
  'host' => Util_Environment::host(),
699
  'module' => 'minify'
700
  );
701
- $w3_cache = new Cache_Xcache( $config );
702
- $cache[0] = new \Minify_Cache_W3TCDerived( $w3_cache );
703
  break;
704
 
705
  case 'wincache':
@@ -709,13 +699,16 @@ class Minify_MinifiedFileRequestHandler {
709
  'host' => Util_Environment::host(),
710
  'module' => 'minify'
711
  );
712
- $w3_cache = new Cache_Wincache( $config );
713
- $cache[0] = new \Minify_Cache_W3TCDerived( $w3_cache );
714
  break;
 
715
 
716
- case 'file':
717
- default:
718
- $cache[0] = new \Minify_Cache_File(
 
 
 
719
  Util_Environment::cache_blog_minify_dir(),
720
  array(
721
  '.htaccess',
@@ -726,11 +719,10 @@ class Minify_MinifiedFileRequestHandler {
726
  $this->_config->get_integer( 'timelimit.cache_flush' ),
727
  ( Util_Environment::blog_id() == 0 ? W3TC_CACHE_MINIFY_DIR : null )
728
  );
729
- break;
730
  }
731
  }
732
 
733
- return $cache[0];
734
  }
735
 
736
  /**
503
  $result = array();
504
  if ( is_array( $files ) && count( $files ) > 0 ) {
505
  foreach ( $files as $file ) {
 
 
506
  if ( Util_Environment::is_url( $file ) ) {
507
  $precached_file = $this->_precache_file( $file, $type );
508
 
512
  Minify_Core::debug_error( sprintf( 'Unable to cache remote file: "%s"', $file ) );
513
  }
514
  } else {
515
+ $file = Util_Environment::url_to_docroot_filename( $file );
516
  $path = Util_Environment::document_root() . '/' . $file;
517
 
518
  if ( file_exists( $path ) ) {
548
 
549
  $message = '<h1>W3TC Minify Error</h1>';
550
 
551
+ if ( $this->_config->get_boolean( 'minify.debug' ) ) {
552
  $message .= sprintf( '<p>%s.</p>', $error );
553
  } else {
554
  $message .= '<p>Enable debug mode to see error message.</p>';
556
 
557
  if ( $quiet ) {
558
  return array(
559
+ 'content' => $message
560
  );
561
  }
562
 
585
  $cache_path = sprintf( '%s/minify_%s.%s', Util_Environment::cache_blog_dir( 'minify' ), md5( $url ), $type );
586
 
587
  if ( !file_exists( $cache_path ) || @filemtime( $cache_path ) < ( time() - $lifetime ) ) {
 
588
  if ( !@is_dir( dirname( $cache_path ) ) ) {
589
+ Util_File::mkdir_from_safe( dirname( $cache_path ), W3TC_CACHE_DIR );
 
590
  }
591
+
592
  Util_Http::download( $url, $cache_path );
593
  }
594
 
617
  * @return object
618
  */
619
  function _get_cache() {
620
+ static $cache = null;
621
+
622
+ if ( is_null( $cache ) ) {
623
+ $inner_cache = null;
624
 
 
625
  switch ( $this->_config->get_string( 'minify.engine' ) ) {
626
  case 'memcached':
627
  $config = array(
632
  'servers' => $this->_config->get_array( 'minify.memcached.servers' ),
633
  'persistent' => $this->_config->get_boolean( 'minify.memcached.persistent' ),
634
  'aws_autodiscovery' => $this->_config->get_boolean( 'minify.memcached.aws_autodiscovery' ),
635
+ 'username' => $this->_config->get_string( 'minify.memcached.username' ),
636
+ 'password' => $this->_config->get_string( 'minify.memcached.password' )
637
  );
638
  if ( class_exists( 'Memcached' ) ) {
639
+ $inner_cache = new Cache_Memcached( $config );
640
+ } elseif ( class_exists( 'Memcache' ) ) {
641
+ $inner_cache = new Cache_Memcache( $config );
642
+ }
 
 
643
  break;
644
 
645
  case 'redis':
650
  'module' => 'minify',
651
  'servers' => $this->_config->get_array( 'minify.redis.servers' ),
652
  'persistent' => $this->_config->get_boolean( 'minify.redis.persistent' ),
653
+ 'dbid' => $this->_config->get_integer( 'minify.redis.dbid' ),
654
+ 'password' => $this->_config->get_string( 'minify.redis.password' )
655
  );
656
+ $inner_cache = new Cache_Redis( $config );
 
 
 
 
657
 
 
658
  break;
659
 
660
  case 'apc':
665
  'module' => 'minify'
666
  );
667
 
668
+ if ( function_exists( 'apcu_store' ) ) {
669
+ $inner_cache = new Cache_Apcu( $config );
670
+ } elseif ( function_exists( 'apc_store' ) ) {
671
+ $inner_cache = new Cache_Apc( $config );
672
+ }
 
673
  break;
674
 
675
  case 'eaccelerator':
679
  'host' => Util_Environment::host(),
680
  'module' => 'minify'
681
  );
682
+ $inner_cache = new Cache_Eaccelerator( $config );
 
683
  break;
684
 
685
  case 'xcache':
689
  'host' => Util_Environment::host(),
690
  'module' => 'minify'
691
  );
692
+ $inner_cache = new Cache_Xcache( $config );
 
693
  break;
694
 
695
  case 'wincache':
699
  'host' => Util_Environment::host(),
700
  'module' => 'minify'
701
  );
702
+ $inner_cache = new Cache_Wincache( $config );
 
703
  break;
704
+ }
705
 
706
+ if ( !is_null( $inner_cache ) ) {
707
+ $cache = new \Minify_Cache_W3TCDerived( $inner_cache );
708
+ } else {
709
+ // case 'file' or fallback
710
+
711
+ $cache = new \Minify_Cache_File(
712
  Util_Environment::cache_blog_minify_dir(),
713
  array(
714
  '.htaccess',
719
  $this->_config->get_integer( 'timelimit.cache_flush' ),
720
  ( Util_Environment::blog_id() == 0 ? W3TC_CACHE_MINIFY_DIR : null )
721
  );
 
722
  }
723
  }
724
 
725
+ return $cache;
726
  }
727
 
728
  /**
Minify_Plugin.php CHANGED
@@ -138,228 +138,265 @@ class Minify_Plugin {
138
  * @return string
139
  */
140
  function ob_callback( $buffer ) {
141
- if ( $buffer != '' && Util_Content::is_html( $buffer ) ) {
142
- if ( $this->can_minify2( $buffer ) ) {
143
- $this->minify_helpers = new _W3_MinifyHelpers( $this->_config );
144
-
145
- /**
146
- * Replace script and style tags
147
- */
148
- $js_enable = $this->_config->get_boolean( 'minify.js.enable' );
149
- $css_enable = $this->_config->get_boolean( 'minify.css.enable' );
150
- $html_enable = $this->_config->get_boolean( 'minify.html.enable' );
151
-
152
- if ( function_exists( 'is_feed' ) && is_feed() ) {
153
- $js_enable = false;
154
- $css_enable = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  }
156
-
157
- $js_enable = apply_filters( 'w3tc_minify_js_enable', $js_enable );
158
- $css_enable = apply_filters( 'w3tc_minify_css_enable', $css_enable );
159
- $html_enable = apply_filters( 'w3tc_minify_html_enable', $html_enable );
160
-
161
- $head_prepend = '';
162
- $body_prepend = '';
163
- $body_append = '';
164
- $embed_extsrcjs = false;
165
- $buffer = apply_filters( 'w3tc_minify_before', $buffer );
166
-
167
-
168
-
169
- if ( $this->_config->get_boolean( 'minify.auto' ) ) {
170
- if ( $js_enable ) {
171
- $minifier = new _W3_MinifyJsAuto( $this->_config,
172
- $buffer, $this->minify_helpers );
173
- $buffer = $minifier->execute();
174
- $this->replaced_scripts =
175
- $minifier->get_debug_minified_urls();
176
  }
177
 
178
- if ( $css_enable ) {
179
- $embed_to_html = $this->_config->get_boolean( 'minify.css.embed' );
180
- $ignore_css_files = $this->_config->get_array( 'minify.reject.files.css' );
181
- $files_to_minify = array();
182
 
183
- $embed_pos = strpos( $buffer, '<!-- W3TC-include-css -->' );
 
 
184
 
 
 
185
 
186
- $buffer = str_replace( '<!-- W3TC-include-css -->', '', $buffer );
187
- if ( $embed_pos === false ) {
188
- if ( preg_match( '~<head(\s+[^>]*)*>~Ui', $buffer, $match, PREG_OFFSET_CAPTURE ) )
189
- $embed_pos = strlen( $match[0][0] ) + $match[0][1];
190
- else
191
- $embed_pos = 0;
192
- }
193
 
194
- $ignore_css_files = array_map( array( '\W3TC\Util_Environment', 'normalize_file' ), $ignore_css_files );
195
- $handled_styles = array();
196
- $style_tags = Minify_Extract::extract_css( $buffer );
197
- $previous_file_was_ignored = false;
198
- foreach ( $style_tags as $style_tag_tuple ) {
199
- $style_tag = $style_tag_tuple[0];
200
- $style_len = strlen( $style_tag );
201
- $tag_pos = strpos( $buffer, $style_tag );
202
- $match = array();
203
- $url = $style_tag_tuple[1];
204
- if ( $this->_config->get_boolean( 'minify.debug' ) ) {
205
- Minify_Core::log( 'adding ' . $url );
206
- }
 
 
 
 
 
 
 
 
207
 
208
- $url = Util_Environment::url_relative_to_full( $url );
209
- $file = Util_Environment::url_to_docroot_filename( $url );
210
-
211
- $do_tag_minification =
212
- $this->minify_helpers->is_file_for_minification( $file ) &&
213
- !in_array( $file, $handled_styles );
214
- $do_tag_minification = apply_filters( 'w3tc_minify_css_do_tag_minification',
215
- $do_tag_minification, $style_tag, $file );
216
-
217
- if ( !$do_tag_minification )
218
- continue;
219
-
220
- $handled_styles[] = $file;
221
- $this->replaced_styles[] = $file;
222
- if ( in_array( $file, $ignore_css_files ) ) {
223
- if ( $tag_pos > $embed_pos ) {
224
- if ( $files_to_minify ) {
225
- $data = array(
226
- 'files_to_minify' => $files_to_minify,
227
- 'embed_pos' => $embed_pos,
228
- 'embed_to_html' => $embed_to_html
229
- );
230
-
231
- $data = apply_filters(
232
- 'w3tc_minify_css_step',
233
- $data );
234
-
235
- $style = $this->get_style_custom(
236
- $data['files_to_minify'],
237
- $data['embed_to_html'] );
238
-
239
- $buffer = substr_replace( $buffer, $style, $embed_pos, 0 );
240
-
241
- $files_to_minify = array();
242
- $style_len = $style_len +strlen( $style );
243
- }
244
- $embed_pos = $embed_pos + $style_len;
245
- $previous_file_was_ignored = true;
246
  }
247
- } else {
248
- $buffer = substr_replace( $buffer, '', $tag_pos, $style_len );
249
- if ( $embed_pos > $tag_pos )
250
- $embed_pos -= $style_len;
251
- elseif ( $previous_file_was_ignored )
252
- $embed_pos = $tag_pos;
253
-
254
- $files_to_minify[] = $file;
255
  }
 
 
256
  }
 
 
 
 
 
 
 
 
 
 
257
 
258
- $data = array(
259
- 'files_to_minify' => $files_to_minify,
260
- 'embed_pos' => $embed_pos,
261
- 'embed_to_html' => $embed_to_html
262
- );
263
 
264
- $data = apply_filters( 'w3tc_minify_css_step',
265
- $data );
266
 
267
- $style = $this->get_style_custom(
268
- $data['files_to_minify'],
269
- $data['embed_to_html'] );
270
- $buffer = substr_replace( $buffer, $style,
271
- $data['embed_pos'], 0 );
272
- }
273
 
274
- $buffer = apply_filters( 'w3tc_minify_processed', $buffer );
275
- } else {
276
- if ( $css_enable ) {
277
- $style = $this->get_style_group( 'include' );
278
 
279
- if ( $style ) {
280
- if ( $this->_custom_location_does_not_exist( '/<!-- W3TC-include-css -->/', $buffer, $style ) )
281
- $head_prepend .= $style;
282
 
283
- $this->remove_styles_group( $buffer, 'include' );
284
- }
285
- }
 
286
 
287
- if ( $js_enable ) {
288
- $embed_type = $this->_config->get_string( 'minify.js.header.embed_type' );
289
- $script = $this->get_script_group( 'include', $embed_type );
290
 
291
- if ( $script ) {
292
- $embed_extsrcjs = $embed_type == 'extsrc' || $embed_type == 'asyncsrc'?true:$embed_extsrcjs;
293
 
294
- if ( $this->_custom_location_does_not_exist( '/<!-- W3TC-include-js-head -->/', $buffer, $script ) )
295
- $head_prepend .= $script;
 
 
 
296
 
297
- $this->remove_scripts_group( $buffer, 'include' );
298
- }
 
299
 
300
- $embed_type = $this->_config->get_string( 'minify.js.body.embed_type' );
301
- $script = $this->get_script_group( 'include-body', $embed_type );
302
 
303
- if ( $script ) {
304
- $embed_extsrcjs = $embed_type == 'extsrc' || $embed_type == 'asyncsrc'?true:$embed_extsrcjs;
305
 
306
- if ( $this->_custom_location_does_not_exist( '/<!-- W3TC-include-js-body-start -->/', $buffer, $script ) )
307
- $body_prepend .= $script;
308
 
309
- $this->remove_scripts_group( $buffer, 'include-body' );
310
- }
 
 
 
 
311
 
312
- $embed_type = $this->_config->get_string( 'minify.js.footer.embed_type' );
313
- $script = $this->get_script_group( 'include-footer', $embed_type );
314
 
315
- if ( $script ) {
316
- $embed_extsrcjs = $embed_type == 'extsrc' || $embed_type == 'asyncsrc'?true:$embed_extsrcjs;
317
 
318
- if ( $this->_custom_location_does_not_exist( '/<!-- W3TC-include-js-body-end -->/', $buffer, $script ) )
319
- $body_append .= $script;
320
 
321
- $this->remove_scripts_group( $buffer, 'include-footer' );
322
- }
323
- }
324
  }
325
-
326
- if ( $head_prepend != '' ) {
327
- $buffer = preg_replace( '~<head(\s+[^>]*)*>~Ui',
328
- '\\0' . $head_prepend, $buffer, 1 );
329
  }
330
 
331
- if ( $body_prepend != '' ) {
332
- $buffer = preg_replace( '~<body(\s+[^>]*)*>~Ui',
333
- '\\0' . $body_prepend, $buffer, 1 );
334
- }
 
 
 
 
335
 
336
- if ( $body_append != '' ) {
337
- $buffer = preg_replace( '~<\\/body>~',
338
- $body_append . '\\0', $buffer, 1 );
339
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
 
341
- if ( $embed_extsrcjs ) {
342
- $script = "
343
  <script type=\"text/javascript\">
344
  " ."var extsrc=null;
345
  ".'(function(){function j(){if(b&&g){document.write=k;document.writeln=l;var f=document.createElement("span");f.innerHTML=b;g.appendChild(f);b=""}}function d(){j();for(var f=document.getElementsByTagName("script"),c=0;c<f.length;c++){var e=f[c],h=e.getAttribute("asyncsrc");if(h){e.setAttribute("asyncsrc","");var a=document.createElement("script");a.async=!0;a.src=h;document.getElementsByTagName("head")[0].appendChild(a)}if(h=e.getAttribute("extsrc")){e.setAttribute("extsrc","");g=document.createElement("span");e.parentNode.insertBefore(g,e);document.write=function(a){b+=a};document.writeln=function(a){b+=a;b+="\n"};a=document.createElement("script");a.async=!0;a.src=h;/msie/i.test(navigator.userAgent)&&!/opera/i.test(navigator.userAgent)?a.onreadystatechange=function(){("loaded"==this.readyState||"complete"==this.readyState)&&d()}:-1!=navigator.userAgent.indexOf("Firefox")||"onerror"in a?(a.onload=d,a.onerror=d):(a.onload=d,a.onreadystatechange=d);document.getElementsByTagName("head")[0].appendChild(a);return}}j();document.write=k;document.writeln=l;for(c=0;c<extsrc.complete.funcs.length;c++)extsrc.complete.funcs[c]()}function i(){arguments.callee.done||(arguments.callee.done=!0,d())}extsrc={complete:function(b){this.complete.funcs.push(b)}};extsrc.complete.funcs=[];var k=document.write,l=document.writeln,b="",g="";document.addEventListener&&document.addEventListener("DOMContentLoaded",i,!1);if(/WebKit/i.test(navigator.userAgent))var m=setInterval(function(){/loaded|complete/.test(document.readyState)&&(clearInterval(m),i())},10);window.onload=i})();' . "
346
  </script>
347
  ";
348
 
349
- $buffer = preg_replace( '~<head(\s+[^>]*)*>~Ui',
350
- '\\0' . $script, $buffer, 1 );
351
- }
352
 
353
- /**
354
- * Minify HTML/Feed
355
- */
356
- if ( $html_enable ) {
357
- try {
358
- $buffer = $this->minify_html( $buffer );
359
- } catch ( \Exception $exception ) {
360
- $this->error = $exception->getMessage();
361
- }
362
- }
363
  }
364
  }
365
 
@@ -730,17 +767,22 @@ class Minify_Plugin {
730
  $template = 'default';
731
  }
732
 
 
 
 
 
 
733
  if ( !empty( $groups[$theme][$template][$location]['files'] ) ) {
734
- $url = $this->format_url_group( $theme, $template, $location, $type );
735
 
736
- if ( $url ) {
737
  $import = ( isset( $groups[$theme][$template][$location]['import'] ) ? (boolean) $groups[$theme][$template][$location]['import'] : false );
738
 
739
- $style = $this->get_style( $url, $import );
740
  }
741
  }
742
 
743
- return $style;
744
  }
745
 
746
  /**
@@ -761,15 +803,21 @@ class Minify_Plugin {
761
  $template = 'default';
762
  }
763
 
 
 
 
 
 
764
  if ( !empty( $groups[$theme][$template][$location]['files'] ) ) {
765
- $url = $this->format_url_group( $theme, $template, $location, $fileType );
766
 
767
- if ( $url ) {
768
- $script = $this->minify_helpers->generate_script_tag( $url, $embed_type );
 
769
  }
770
  }
771
 
772
- return $script;
773
  }
774
 
775
  /**
@@ -778,20 +826,27 @@ class Minify_Plugin {
778
  * @return string
779
  */
780
  function get_style_custom( $files, $embed_to_html = false ) {
 
 
 
 
 
781
  if ( count( $files ) ) {
782
  if ( $embed_to_html ) {
783
- return $this->minify_helpers->get_minified_content_for_files(
784
- $files, 'css' );
 
785
  } else {
786
- $url = $this->minify_helpers->get_minify_url_for_files( $files,
787
- 'css' );
788
- if ( !is_null( $url ) ) {
789
- return $this->get_style( $url, false, false );
 
790
  }
791
  }
792
  }
793
 
794
- return '';
795
  }
796
 
797
  /**
@@ -1036,6 +1091,8 @@ class Minify_Plugin {
1036
 
1037
  foreach ( $reject_uri as $expr ) {
1038
  $expr = trim( $expr );
 
 
1039
  if ( $expr != '' && preg_match( '~' . $expr . '~i', $_SERVER['REQUEST_URI'] ) ) {
1040
  return false;
1041
  }
@@ -1117,10 +1174,10 @@ class _W3_MinifyHelpers {
1117
  $minify = Dispatcher::component( 'Minify_MinifiedFileRequestHandler' );
1118
 
1119
  $m = $minify->process( $minify_filename, true );
1120
- if ( isset( $m['content']['content'] ) )
1121
- $style = $m['content']['content'];
1122
  else
1123
- $style = '';
1124
 
1125
  return "<style type=\"text/css\" media=\"all\">$style</style>\r\n";
1126
  }
@@ -1174,20 +1231,33 @@ class _W3_MinifyHelpers {
1174
  * @param string $file
1175
  * @return bool
1176
  */
1177
- public function is_file_for_minification( $file ) {
1178
  static $external;
1179
- if ( !isset( $external ) )
 
1180
  $external = $this->config->get_array( 'minify.cache.files' );
 
 
1181
 
1182
- foreach ( $external as $ext ) {
1183
- if ( preg_match( '#'.Util_Environment::get_url_regexp( $ext ).'#', $file ) ) {
1184
- if ( $this->debug ) {
1185
- Minify_Core::log(
1186
- 'is_file_for_minification: whilelisted ' . $file );
1187
- }
 
 
 
 
 
 
1188
 
1189
- return true;
 
 
1190
  }
 
 
1191
  }
1192
 
1193
 
@@ -1201,7 +1271,7 @@ class _W3_MinifyHelpers {
1201
  ' for ' . $file );
1202
  }
1203
 
1204
- return false;
1205
  }
1206
 
1207
  if ( Util_Environment::is_url( $file_normalized ) ) {
@@ -1210,7 +1280,7 @@ class _W3_MinifyHelpers {
1210
  'is_file_for_minification: its url ' . $file );
1211
  }
1212
 
1213
- return false;
1214
  }
1215
 
1216
  $path = Util_Environment::document_root() . '/' . $file;
@@ -1221,7 +1291,7 @@ class _W3_MinifyHelpers {
1221
  'is_file_for_minification: file doesnt exists ' . $path );
1222
  }
1223
 
1224
- return false;
1225
  }
1226
 
1227
  if ( $this->debug ) {
@@ -1230,7 +1300,19 @@ class _W3_MinifyHelpers {
1230
  ' path ' . $path );
1231
  }
1232
 
1233
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
1234
  }
1235
  }
1236
 
@@ -1438,7 +1520,8 @@ class _W3_MinifyJsAuto {
1438
  $script_src = Util_Environment::url_relative_to_full( $script_src );
1439
  $file = Util_Environment::url_to_docroot_filename( $script_src );
1440
 
1441
- $step1 = $this->minify_helpers->is_file_for_minification( $file );
 
1442
  $step2 = !in_array( $file, $this->ignore_js_files );
1443
 
1444
  $do_tag_minification = $step1 && $step2;
@@ -1503,18 +1586,6 @@ class _W3_MinifyJsAuto {
1503
  // find embed position
1504
  $embed_pos = $this->embed_pos;
1505
 
1506
- if ( $this->minify_group_number <= 0 ) {
1507
- // try forced embed position
1508
- $forced_embed_pos = strpos( $this->buffer,
1509
- '<!-- W3TC-include-js-head -->' );
1510
-
1511
- if ( $forced_embed_pos !== false ) {
1512
- $this->buffer = str_replace( '<!-- W3TC-include-js-head -->', '',
1513
- $this->buffer );
1514
- $embed_pos = $forced_embed_pos;
1515
- }
1516
- }
1517
-
1518
  // build minified script tag
1519
  $data = array(
1520
  'files_to_minify' => $this->files_to_minify,
@@ -1542,6 +1613,11 @@ class _W3_MinifyJsAuto {
1542
  $data );
1543
  $this->buffer = $data['buffer'];
1544
 
 
 
 
 
 
1545
  // replace
1546
  $this->buffer = substr_replace( $this->buffer,
1547
  $data['script_to_embed_body'], $data['embed_pos'], 0 );
138
  * @return string
139
  */
140
  function ob_callback( $buffer ) {
141
+ $enable = Util_Content::is_html( $buffer ) &&
142
+ $this->can_minify2( $buffer );
143
+ $enable = apply_filters( 'w3tc_minify_enable', $enable );
144
+ if ( !$enable )
145
+ return $buffer;
146
+
147
+
148
+ $this->minify_helpers = new _W3_MinifyHelpers( $this->_config );
149
+
150
+ /**
151
+ * Replace script and style tags
152
+ */
153
+ $js_enable = $this->_config->get_boolean( 'minify.js.enable' );
154
+ $css_enable = $this->_config->get_boolean( 'minify.css.enable' );
155
+ $html_enable = $this->_config->get_boolean( 'minify.html.enable' );
156
+
157
+ if ( function_exists( 'is_feed' ) && is_feed() ) {
158
+ $js_enable = false;
159
+ $css_enable = false;
160
+ }
161
+
162
+ $js_enable = apply_filters( 'w3tc_minify_js_enable', $js_enable );
163
+ $css_enable = apply_filters( 'w3tc_minify_css_enable', $css_enable );
164
+ $html_enable = apply_filters( 'w3tc_minify_html_enable', $html_enable );
165
+
166
+ $head_prepend = '';
167
+ $body_prepend = '';
168
+ $body_append = '';
169
+ $embed_extsrcjs = false;
170
+ $buffer = apply_filters( 'w3tc_minify_before', $buffer );
171
+
172
+
173
+
174
+ if ( $this->_config->get_boolean( 'minify.auto' ) ) {
175
+ if ( $js_enable ) {
176
+ $minifier = new _W3_MinifyJsAuto( $this->_config,
177
+ $buffer, $this->minify_helpers );
178
+ $buffer = $minifier->execute();
179
+ $this->replaced_scripts =
180
+ $minifier->get_debug_minified_urls();
181
+ }
182
+
183
+ if ( $css_enable ) {
184
+ $embed_to_html = $this->_config->get_boolean( 'minify.css.embed' );
185
+ $ignore_css_files = $this->_config->get_array( 'minify.reject.files.css' );
186
+ $files_to_minify = array();
187
+
188
+ $embed_pos = strpos( $buffer, '<!-- W3TC-include-css -->' );
189
+
190
+
191
+ $buffer = str_replace( '<!-- W3TC-include-css -->', '', $buffer );
192
+ if ( $embed_pos === false ) {
193
+ if ( preg_match( '~<head(\s+[^>]*)*>~Ui', $buffer, $match, PREG_OFFSET_CAPTURE ) )
194
+ $embed_pos = strlen( $match[0][0] ) + $match[0][1];
195
+ else
196
+ $embed_pos = 0;
197
  }
198
+
199
+ $ignore_css_files = array_map( array( '\W3TC\Util_Environment', 'normalize_file' ), $ignore_css_files );
200
+ $handled_styles = array();
201
+ $style_tags = Minify_Extract::extract_css( $buffer );
202
+ $previous_file_was_ignored = false;
203
+ foreach ( $style_tags as $style_tag_tuple ) {
204
+ $style_tag = $style_tag_tuple[0];
205
+ $style_len = strlen( $style_tag );
206
+ $tag_pos = strpos( $buffer, $style_tag );
207
+ $match = array();
208
+ $url = $style_tag_tuple[1];
209
+ if ( $this->_config->get_boolean( 'minify.debug' ) ) {
210
+ Minify_Core::log( 'adding ' . $url );
 
 
 
 
 
 
 
211
  }
212
 
213
+ $url = Util_Environment::url_relative_to_full( $url );
214
+ $file = Util_Environment::url_to_docroot_filename( $url );
 
 
215
 
216
+ $include_type = $this->minify_helpers->is_file_for_minification( $url, $file );
217
+ if ( $include_type == 'url' )
218
+ $file = $url;
219
 
220
+ $do_tag_minification = !empty( $include_type ) &&
221
+ !in_array( $file, $handled_styles );
222
 
223
+ $do_tag_minification = apply_filters( 'w3tc_minify_css_do_tag_minification',
224
+ $do_tag_minification, $style_tag, $file );
 
 
 
 
 
225
 
226
+ if ( !$do_tag_minification )
227
+ continue;
228
+
229
+ $handled_styles[] = $file;
230
+ $this->replaced_styles[] = $file;
231
+ if ( in_array( $file, $ignore_css_files ) ) {
232
+ if ( $tag_pos > $embed_pos ) {
233
+ if ( $files_to_minify ) {
234
+ $data = array(
235
+ 'files_to_minify' => $files_to_minify,
236
+ 'embed_pos' => $embed_pos,
237
+ 'embed_to_html' => $embed_to_html
238
+ );
239
+
240
+ $data = apply_filters(
241
+ 'w3tc_minify_css_step',
242
+ $data );
243
+
244
+ $style = $this->get_style_custom(
245
+ $data['files_to_minify'],
246
+ $data['embed_to_html'] );
247
 
248
+ if ( $this->_config->get_boolean( 'minify.css.http2push' ) ) {
249
+ $this->minify_helpers->http2_header_add( $style['url'],
250
+ 'style' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  }
252
+
253
+ $buffer = substr_replace( $buffer, $style['body'], $embed_pos, 0 );
254
+
255
+ $files_to_minify = array();
256
+ $style_len = $style_len + strlen( $style['body'] );
 
 
 
257
  }
258
+ $embed_pos = $embed_pos + $style_len;
259
+ $previous_file_was_ignored = true;
260
  }
261
+ } else {
262
+ $buffer = substr_replace( $buffer, '', $tag_pos, $style_len );
263
+ if ( $embed_pos > $tag_pos )
264
+ $embed_pos -= $style_len;
265
+ elseif ( $previous_file_was_ignored )
266
+ $embed_pos = $tag_pos;
267
+
268
+ $files_to_minify[] = $file;
269
+ }
270
+ }
271
 
272
+ $data = array(
273
+ 'files_to_minify' => $files_to_minify,
274
+ 'embed_pos' => $embed_pos,
275
+ 'embed_to_html' => $embed_to_html
276
+ );
277
 
278
+ $data = apply_filters( 'w3tc_minify_css_step',
279
+ $data );
280
 
281
+ $style = $this->get_style_custom(
282
+ $data['files_to_minify'],
283
+ $data['embed_to_html'] );
 
 
 
284
 
285
+ if ( $this->_config->get_boolean( 'minify.css.http2push' ) ) {
286
+ $this->minify_helpers->http2_header_add( $style['url'],
287
+ 'style' );
288
+ }
289
 
290
+ $buffer = substr_replace( $buffer, $style['body'],
291
+ $data['embed_pos'], 0 );
292
+ }
293
 
294
+ $buffer = apply_filters( 'w3tc_minify_processed', $buffer );
295
+ } else {
296
+ if ( $css_enable ) {
297
+ $style = $this->get_style_group( 'include' );
298
 
299
+ if ( $style['body'] ) {
300
+ if ( $this->_custom_location_does_not_exist( '/<!-- W3TC-include-css -->/', $buffer, $style['body'] ) )
301
+ $head_prepend .= $style['body'];
302
 
303
+ $this->remove_styles_group( $buffer, 'include' );
304
+ }
305
 
306
+ if ( $this->_config->get_boolean( 'minify.css.http2push' ) ) {
307
+ $this->minify_helpers->http2_header_add( $style['url'],
308
+ 'style' );
309
+ }
310
+ }
311
 
312
+ if ( $js_enable ) {
313
+ $embed_type = $this->_config->get_string( 'minify.js.header.embed_type' );
314
+ $http2push = $this->_config->get_boolean( 'minify.js.http2push' );
315
 
316
+ $script = $this->get_script_group( 'include', $embed_type );
 
317
 
318
+ if ( $script['body'] ) {
319
+ $embed_extsrcjs = $embed_type == 'extsrc' || $embed_type == 'asyncsrc'?true:$embed_extsrcjs;
320
 
321
+ if ( $this->_custom_location_does_not_exist( '/<!-- W3TC-include-js-head -->/', $buffer, $script['body'] ) )
322
+ $head_prepend .= $script['body'];
323
 
324
+ $this->remove_scripts_group( $buffer, 'include' );
325
+ }
326
+ if ( $http2push ) {
327
+ $this->minify_helpers->http2_header_add( $script['url'],
328
+ 'script' );
329
+ }
330
 
331
+ $embed_type = $this->_config->get_string( 'minify.js.body.embed_type' );
332
+ $script = $this->get_script_group( 'include-body', $embed_type );
333
 
334
+ if ( $script['body'] ) {
335
+ $embed_extsrcjs = $embed_type == 'extsrc' || $embed_type == 'asyncsrc'?true:$embed_extsrcjs;
336
 
337
+ if ( $this->_custom_location_does_not_exist( '/<!-- W3TC-include-js-body-start -->/', $buffer, $script['body'] ) )
338
+ $body_prepend .= $script['body'];
339
 
340
+ $this->remove_scripts_group( $buffer, 'include-body' );
 
 
341
  }
342
+ if ( $http2push ) {
343
+ $this->minify_helpers->http2_header_add( $script['url'],
344
+ 'script' );
 
345
  }
346
 
347
+ $embed_type = $this->_config->get_string( 'minify.js.footer.embed_type' );
348
+ $script = $this->get_script_group( 'include-footer', $embed_type );
349
+
350
+ if ( $script['body'] ) {
351
+ $embed_extsrcjs = $embed_type == 'extsrc' || $embed_type == 'asyncsrc'?true:$embed_extsrcjs;
352
+
353
+ if ( $this->_custom_location_does_not_exist( '/<!-- W3TC-include-js-body-end -->/', $buffer, $script['body'] ) )
354
+ $body_append .= $script['body'];
355
 
356
+ $this->remove_scripts_group( $buffer, 'include-footer' );
 
 
357
  }
358
+ if ( $http2push ) {
359
+ $this->minify_helpers->http2_header_add( $script['url'],
360
+ 'script' );
361
+ }
362
+ }
363
+ }
364
+
365
+ if ( $head_prepend != '' ) {
366
+ $buffer = preg_replace( '~<head(\s+[^>]*)*>~Ui',
367
+ '\\0' . $head_prepend, $buffer, 1 );
368
+ }
369
+
370
+ if ( $body_prepend != '' ) {
371
+ $buffer = preg_replace( '~<body(\s+[^>]*)*>~Ui',
372
+ '\\0' . $body_prepend, $buffer, 1 );
373
+ }
374
+
375
+ if ( $body_append != '' ) {
376
+ $buffer = preg_replace( '~<\\/body>~',
377
+ $body_append . '\\0', $buffer, 1 );
378
+ }
379
 
380
+ if ( $embed_extsrcjs ) {
381
+ $script = "
382
  <script type=\"text/javascript\">
383
  " ."var extsrc=null;
384
  ".'(function(){function j(){if(b&&g){document.write=k;document.writeln=l;var f=document.createElement("span");f.innerHTML=b;g.appendChild(f);b=""}}function d(){j();for(var f=document.getElementsByTagName("script"),c=0;c<f.length;c++){var e=f[c],h=e.getAttribute("asyncsrc");if(h){e.setAttribute("asyncsrc","");var a=document.createElement("script");a.async=!0;a.src=h;document.getElementsByTagName("head")[0].appendChild(a)}if(h=e.getAttribute("extsrc")){e.setAttribute("extsrc","");g=document.createElement("span");e.parentNode.insertBefore(g,e);document.write=function(a){b+=a};document.writeln=function(a){b+=a;b+="\n"};a=document.createElement("script");a.async=!0;a.src=h;/msie/i.test(navigator.userAgent)&&!/opera/i.test(navigator.userAgent)?a.onreadystatechange=function(){("loaded"==this.readyState||"complete"==this.readyState)&&d()}:-1!=navigator.userAgent.indexOf("Firefox")||"onerror"in a?(a.onload=d,a.onerror=d):(a.onload=d,a.onreadystatechange=d);document.getElementsByTagName("head")[0].appendChild(a);return}}j();document.write=k;document.writeln=l;for(c=0;c<extsrc.complete.funcs.length;c++)extsrc.complete.funcs[c]()}function i(){arguments.callee.done||(arguments.callee.done=!0,d())}extsrc={complete:function(b){this.complete.funcs.push(b)}};extsrc.complete.funcs=[];var k=document.write,l=document.writeln,b="",g="";document.addEventListener&&document.addEventListener("DOMContentLoaded",i,!1);if(/WebKit/i.test(navigator.userAgent))var m=setInterval(function(){/loaded|complete/.test(document.readyState)&&(clearInterval(m),i())},10);window.onload=i})();' . "
385
  </script>
386
  ";
387
 
388
+ $buffer = preg_replace( '~<head(\s+[^>]*)*>~Ui',
389
+ '\\0' . $script, $buffer, 1 );
390
+ }
391
 
392
+ /**
393
+ * Minify HTML/Feed
394
+ */
395
+ if ( $html_enable ) {
396
+ try {
397
+ $buffer = $this->minify_html( $buffer );
398
+ } catch ( \Exception $exception ) {
399
+ $this->error = $exception->getMessage();
 
 
400
  }
401
  }
402
 
767
  $template = 'default';
768
  }
769
 
770
+ $return = array(
771
+ 'url' => null,
772
+ 'body' => ''
773
+ );
774
+
775
  if ( !empty( $groups[$theme][$template][$location]['files'] ) ) {
776
+ $return['url'] = $this->format_url_group( $theme, $template, $location, $type );
777
 
778
+ if ( $return['url'] ) {
779
  $import = ( isset( $groups[$theme][$template][$location]['import'] ) ? (boolean) $groups[$theme][$template][$location]['import'] : false );
780
 
781
+ $return['body'] = $this->get_style( $return['url'], $import );
782
  }
783
  }
784
 
785
+ return $return;
786
  }
787
 
788
  /**
803
  $template = 'default';
804
  }
805
 
806
+ $return = array(
807
+ 'url' => null,
808
+ 'body' => ''
809
+ );
810
+
811
  if ( !empty( $groups[$theme][$template][$location]['files'] ) ) {
812
+ $return['url'] = $this->format_url_group( $theme, $template, $location, $fileType );
813
 
814
+ if ( $return['url'] ) {
815
+ $return['body'] = $this->minify_helpers->generate_script_tag(
816
+ $return['url'], $embed_type );
817
  }
818
  }
819
 
820
+ return $return;
821
  }
822
 
823
  /**
826
  * @return string
827
  */
828
  function get_style_custom( $files, $embed_to_html = false ) {
829
+ $return = array(
830
+ 'url' => null,
831
+ 'body' => ''
832
+ );
833
+
834
  if ( count( $files ) ) {
835
  if ( $embed_to_html ) {
836
+ $return['body'] =
837
+ $this->minify_helpers->get_minified_content_for_files(
838
+ $files, 'css' );
839
  } else {
840
+ $return['url'] = $this->minify_helpers->get_minify_url_for_files(
841
+ $files, 'css' );
842
+ if ( !is_null( $return['url'] ) ) {
843
+ $return['body'] = $this->get_style( $return['url'], false,
844
+ false );
845
  }
846
  }
847
  }
848
 
849
+ return $return;
850
  }
851
 
852
  /**
1091
 
1092
  foreach ( $reject_uri as $expr ) {
1093
  $expr = trim( $expr );
1094
+ $expr = str_replace( '~', '\~', $expr );
1095
+
1096
  if ( $expr != '' && preg_match( '~' . $expr . '~i', $_SERVER['REQUEST_URI'] ) ) {
1097
  return false;
1098
  }
1174
  $minify = Dispatcher::component( 'Minify_MinifiedFileRequestHandler' );
1175
 
1176
  $m = $minify->process( $minify_filename, true );
1177
+ if ( isset( $m['content'] ) )
1178
+ $style = $m['content'];
1179
  else
1180
+ $style = 'not set';
1181
 
1182
  return "<style type=\"text/css\" media=\"all\">$style</style>\r\n";
1183
  }
1231
  * @param string $file
1232
  * @return bool
1233
  */
1234
+ public function is_file_for_minification( $url, $file ) {
1235
  static $external;
1236
+ static $external_regexp;
1237
+ if ( !isset( $external ) ) {
1238
  $external = $this->config->get_array( 'minify.cache.files' );
1239
+ $external_regexp = $this->config->get_boolean( 'minify.cache.files_regexp' );
1240
+ }
1241
 
1242
+ foreach ( $external as $item ) {
1243
+ if ( empty( $item ) )
1244
+ continue;
1245
+
1246
+ if ( $external_regexp ) {
1247
+ $item = str_replace( '~', '\~', $item );
1248
+ if ( ! preg_match( '~' . $item . '~', $url ) )
1249
+ continue;
1250
+ } else {
1251
+ if ( ! preg_match( '~^' . Util_Environment::get_url_regexp( $item ) . '~', $url ) )
1252
+ continue;
1253
+ }
1254
 
1255
+ if ( $this->debug ) {
1256
+ Minify_Core::log(
1257
+ 'is_file_for_minification: whilelisted ' . $url . ' by ' . $item );
1258
  }
1259
+
1260
+ return 'url';
1261
  }
1262
 
1263
 
1271
  ' for ' . $file );
1272
  }
1273
 
1274
+ return '';
1275
  }
1276
 
1277
  if ( Util_Environment::is_url( $file_normalized ) ) {
1280
  'is_file_for_minification: its url ' . $file );
1281
  }
1282
 
1283
+ return '';
1284
  }
1285
 
1286
  $path = Util_Environment::document_root() . '/' . $file;
1291
  'is_file_for_minification: file doesnt exists ' . $path );
1292
  }
1293
 
1294
+ return '';
1295
  }
1296
 
1297
  if ( $this->debug ) {
1300
  ' path ' . $path );
1301
  }
1302
 
1303
+ return 'file';
1304
+ }
1305
+
1306
+ /**
1307
+ * Sends HTTP/2 push header
1308
+ */
1309
+ public function http2_header_add( $url, $as ) {
1310
+ if ( empty( $url ) )
1311
+ return;
1312
+
1313
+ // Cloudflare needs URI without host
1314
+ $uri = Util_Environment::url_to_uri( $url );
1315
+ header( 'Link: <' . $uri . '>; rel=preload; as=' . $as, false );
1316
  }
1317
  }
1318
 
1520
  $script_src = Util_Environment::url_relative_to_full( $script_src );
1521
  $file = Util_Environment::url_to_docroot_filename( $script_src );
1522
 
1523
+ $step1_result = $this->minify_helpers->is_file_for_minification( $script_src, $file );
1524
+ $step1 = !empty( $step1_result );
1525
  $step2 = !in_array( $file, $this->ignore_js_files );
1526
 
1527
  $do_tag_minification = $step1 && $step2;
1586
  // find embed position
1587
  $embed_pos = $this->embed_pos;
1588
 
 
 
 
 
 
 
 
 
 
 
 
 
1589
  // build minified script tag
1590
  $data = array(
1591
  'files_to_minify' => $this->files_to_minify,
1613
  $data );
1614
  $this->buffer = $data['buffer'];
1615
 
1616
+ if ( $this->config->get_boolean( 'minify.js.http2push' ) ) {
1617
+ $this->minify_helpers->http2_header_add(
1618
+ $data['script_to_embed_url'], 'script' );
1619
+ }
1620
+
1621
  // replace
1622
  $this->buffer = substr_replace( $this->buffer,
1623
  $data['script_to_embed_body'], $data['embed_pos'], 0 );
Minify_Plugin_Admin.php CHANGED
@@ -188,16 +188,16 @@ class Minify_Plugin_Admin {
188
  if ( $c->get_string( 'minify.engine' ) == 'memcached' ) {
189
  $summary['memcached_servers']['minify'] = array(
190
  'servers' => $c->get_array( 'minify.memcached.servers' ),
191
- 'username' => $c->get_boolean( 'minify.memcached.username' ),
192
- 'password' => $c->get_boolean( 'minify.memcached.password' ),
193
  'name' => __( 'Minification', 'w3-total-cache' )
194
  );
195
  } elseif ( $c->get_string( 'minify.engine' ) == 'redis' ) {
196
  $summary['redis_servers']['minify'] = array(
197
  'servers' => $c->get_array( 'minify.redis.servers' ),
198
  'username' => $c->get_boolean( 'minify.redis.username' ),
199
- 'dbid' => $c->get_boolean( 'minify.redis.dbid' ),
200
- 'password' => $c->get_boolean( 'minify.redis.password' ),
201
  'name' => __( 'Minification', 'w3-total-cache' )
202
  );
203
  }
@@ -244,7 +244,7 @@ class Minify_Plugin_Admin {
244
  list( $v, $should_count ) =
245
  Util_UsageStatistics::get_or_init_size_transient(
246
  'w3tc_ustats_minify_size', $summary );
247
- if ( $should_count || true ) {
248
  $h = Dispatcher::component( 'Minify_MinifiedFileRequestHandler' );
249
  $stats = $h->get_stats_size( $summary['timeout_time'] );
250
 
188
  if ( $c->get_string( 'minify.engine' ) == 'memcached' ) {
189
  $summary['memcached_servers']['minify'] = array(
190
  'servers' => $c->get_array( 'minify.memcached.servers' ),
191
+ 'username' => $c->get_string( 'minify.memcached.username' ),
192
+ 'password' => $c->get_string( 'minify.memcached.password' ),
193
  'name' => __( 'Minification', 'w3-total-cache' )
194
  );
195
  } elseif ( $c->get_string( 'minify.engine' ) == 'redis' ) {
196
  $summary['redis_servers']['minify'] = array(
197
  'servers' => $c->get_array( 'minify.redis.servers' ),
198
  'username' => $c->get_boolean( 'minify.redis.username' ),
199
+ 'dbid' => $c->get_integer( 'minify.redis.dbid' ),
200
+ 'password' => $c->get_string( 'minify.redis.password' ),
201
  'name' => __( 'Minification', 'w3-total-cache' )
202
  );
203
  }
244
  list( $v, $should_count ) =
245
  Util_UsageStatistics::get_or_init_size_transient(
246
  'w3tc_ustats_minify_size', $summary );
247
+ if ( $should_count ) {
248
  $h = Dispatcher::component( 'Minify_MinifiedFileRequestHandler' );
249
  $stats = $h->get_stats_size( $summary['timeout_time'] );
250
 
ObjectCache_Plugin.php CHANGED
@@ -192,14 +192,14 @@ class ObjectCache_Plugin {
192
  */
193
  function on_change_option( $option ) {
194
  static $flushed = false;
195
-
196
  if ( !$flushed ) {
197
  if ( $option != 'cron' ) {
198
  $flush = Dispatcher::component( 'CacheFlush' );
199
  $flush->objectcache_flush();
200
  $flushed = true;
201
  }
202
- }
203
  }
204
 
205
  /**
192
  */
193
  function on_change_option( $option ) {
194
  static $flushed = false;
195
+ /*
196
  if ( !$flushed ) {
197
  if ( $option != 'cron' ) {
198
  $flush = Dispatcher::component( 'CacheFlush' );
199
  $flush->objectcache_flush();
200
  $flushed = true;
201
  }
202
+ }*/
203
  }
204
 
205
  /**
ObjectCache_Plugin_Admin.php CHANGED
@@ -69,16 +69,16 @@ class ObjectCache_Plugin_Admin {
69
  if ( $c->get_string( 'objectcache.engine' ) == 'memcached' ) {
70
  $summary['memcached_servers']['objectcache'] = array(
71
  'servers' => $c->get_array( 'objectcache.memcached.servers' ),
72
- 'username' => $c->get_boolean( 'objectcache.memcached.username' ),
73
- 'password' => $c->get_boolean( 'objectcache.memcached.password' ),
74
  'name' => __( 'Object Cache', 'w3-total-cache' )
75
  );
76
  } elseif ( $c->get_string( 'objectcache.engine' ) == 'redis' ) {
77
  $summary['redis_servers']['objectcache'] = array(
78
  'servers' => $c->get_array( 'objectcache.redis.servers' ),
79
  'username' => $c->get_boolean( 'objectcache.redis.username' ),
80
- 'dbid' => $c->get_boolean( 'objectcache.redis.dbid' ),
81
- 'password' => $c->get_boolean( 'objectcache.redis.password' ),
82
  'name' => __( 'Object Cache', 'w3-total-cache' )
83
  );
84
  }
69
  if ( $c->get_string( 'objectcache.engine' ) == 'memcached' ) {
70
  $summary['memcached_servers']['objectcache'] = array(
71
  'servers' => $c->get_array( 'objectcache.memcached.servers' ),
72
+ 'username' => $c->get_string( 'objectcache.memcached.username' ),
73
+ 'password' => $c->get_string( 'objectcache.memcached.password' ),
74
  'name' => __( 'Object Cache', 'w3-total-cache' )
75
  );
76
  } elseif ( $c->get_string( 'objectcache.engine' ) == 'redis' ) {
77
  $summary['redis_servers']['objectcache'] = array(
78
  'servers' => $c->get_array( 'objectcache.redis.servers' ),
79
  'username' => $c->get_boolean( 'objectcache.redis.username' ),
80
+ 'dbid' => $c->get_integer( 'objectcache.redis.dbid' ),
81
+ 'password' => $c->get_string( 'objectcache.redis.password' ),
82
  'name' => __( 'Object Cache', 'w3-total-cache' )
83
  );
84
  }
ObjectCache_WpObjectCache_Regular.php CHANGED
@@ -144,6 +144,7 @@ class ObjectCache_WpObjectCache_Regular {
144
 
145
  $key = $this->_get_cache_key( $id, $group );
146
  $internal = isset( $this->cache[$key] );
 
147
 
148
  if ( $internal && !$force ) {
149
  $found = true;
@@ -153,12 +154,24 @@ class ObjectCache_WpObjectCache_Regular {
153
  $this->_check_can_cache_runtime( $group ) ) {
154
  $cache = $this->_get_cache( null, $group );
155
  $v = $cache->get( $key );
 
 
 
 
 
 
 
 
 
156
  if ( is_array( $v ) && $v['content'] != null ) {
157
  $found = true;
158
  $value = $v['content'];
159
- } else
 
160
  $value = false;
 
161
  } else {
 
162
  $value = false;
163
  }
164
 
@@ -170,14 +183,20 @@ class ObjectCache_WpObjectCache_Regular {
170
  $value = clone $value;
171
  }
172
 
 
 
 
 
 
 
 
 
173
  $this->cache[$key] = $value;
174
  $this->cache_total++;
175
 
176
  if ( $value !== false ) {
177
- $cached = true;
178
  $this->cache_hits++;
179
  } else {
180
- $cached = false;
181
  $this->cache_misses++;
182
  }
183
 
@@ -192,11 +211,27 @@ class ObjectCache_WpObjectCache_Regular {
192
  $group = 'default';
193
  }
194
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  $this->debug_info[] = array(
196
  'id' => $id,
197
  'group' => $group,
198
- 'cached' => $cached,
199
- 'internal' => $internal,
200
  'data_size' => ( $value ? strlen( serialize( $value ) ) : '' ),
201
  'time' => $time
202
  );
@@ -222,6 +257,8 @@ class ObjectCache_WpObjectCache_Regular {
222
  }
223
 
224
  $this->cache[$key] = $data;
 
 
225
 
226
  if ( $this->_caching &&
227
  !in_array( $group, $this->nonpersistent_groups ) &&
@@ -239,11 +276,28 @@ class ObjectCache_WpObjectCache_Regular {
239
  }
240
 
241
  $v = array( 'content' => $data );
242
- return $cache->set( $key, $v,
243
  ( $expire ? $expire : $this->_lifetime ) );
 
244
  }
245
 
246
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  }
248
 
249
  /**
@@ -260,16 +314,31 @@ class ObjectCache_WpObjectCache_Regular {
260
  }
261
 
262
  $key = $this->_get_cache_key( $id, $group );
263
-
264
  unset( $this->cache[$key] );
265
 
266
  if ( $this->_caching && !in_array( $group, $this->nonpersistent_groups ) ) {
267
  $cache = $this->_get_cache( null, $group );
 
 
268
 
269
- return $cache->delete( $key );
 
 
270
  }
271
 
272
- return true;
 
 
 
 
 
 
 
 
 
 
 
273
  }
274
 
275
  /**
@@ -324,7 +393,7 @@ class ObjectCache_WpObjectCache_Regular {
324
  *
325
  * @return boolean
326
  */
327
- function flush() {
328
  $this->cache = array();
329
 
330
  global $w3_multisite_blogs;
@@ -341,6 +410,17 @@ class ObjectCache_WpObjectCache_Regular {
341
  $cache->flush();
342
  }
343
 
 
 
 
 
 
 
 
 
 
 
 
344
  return true;
345
  }
346
 
@@ -424,6 +504,108 @@ class ObjectCache_WpObjectCache_Regular {
424
  return $value;
425
  }
426
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
427
  /**
428
  * Print Object Cache stats
429
  *
@@ -494,16 +676,7 @@ class ObjectCache_WpObjectCache_Regular {
494
  if ( in_array( $group, $this->global_groups ) )
495
  $blog_id = 0;
496
 
497
- $key_cache_id = $blog_id . $group . $id;
498
-
499
- if ( isset( $this->_key_cache[$key_cache_id] ) ) {
500
- $key = $this->_key_cache[$key_cache_id];
501
- } else {
502
- $key = md5( $blog_id . $group . $id );
503
- $this->_key_cache[$key_cache_id] = $key;
504
- }
505
-
506
- return $key;
507
  }
508
 
509
  public function get_usage_statistics_cache_config() {
@@ -515,8 +688,8 @@ class ObjectCache_WpObjectCache_Regular {
515
  'servers' => $this->_config->get_array( 'objectcache.memcached.servers' ),
516
  'persistent' => $this->_config->get_boolean( 'objectcache.memcached.persistent' ),
517
  'aws_autodiscovery' => $this->_config->get_boolean( 'objectcache.memcached.aws_autodiscovery' ),
518
- 'username' => $this->_config->get_boolean( 'objectcache.memcached.username' ),
519
- 'password' => $this->_config->get_boolean( 'objectcache.memcached.password' )
520
  );
521
  break;
522
 
@@ -524,8 +697,8 @@ class ObjectCache_WpObjectCache_Regular {
524
  $engineConfig = array(
525
  'servers' => $this->_config->get_array( 'objectcache.redis.servers' ),
526
  'persistent' => $this->_config->get_boolean( 'objectcache.redis.persistent' ),
527
- 'dbid' => $this->_config->get_boolean( 'objectcache.redis.dbid' ),
528
- 'password' => $this->_config->get_boolean( 'objectcache.redis.password' )
529
  );
530
  break;
531
 
@@ -561,8 +734,8 @@ class ObjectCache_WpObjectCache_Regular {
561
  'servers' => $this->_config->get_array( 'objectcache.memcached.servers' ),
562
  'persistent' => $this->_config->get_boolean( 'objectcache.memcached.persistent' ),
563
  'aws_autodiscovery' => $this->_config->get_boolean( 'objectcache.memcached.aws_autodiscovery' ),
564
- 'username' => $this->_config->get_boolean( 'objectcache.memcached.username' ),
565
- 'password' => $this->_config->get_boolean( 'objectcache.memcached.password' )
566
  );
567
  break;
568
 
@@ -570,8 +743,8 @@ class ObjectCache_WpObjectCache_Regular {
570
  $engineConfig = array(
571
  'servers' => $this->_config->get_array( 'objectcache.redis.servers' ),
572
  'persistent' => $this->_config->get_boolean( 'objectcache.redis.persistent' ),
573
- 'dbid' => $this->_config->get_boolean( 'objectcache.redis.dbid' ),
574
- 'password' => $this->_config->get_boolean( 'objectcache.redis.password' )
575
  );
576
  break;
577
 
@@ -603,6 +776,15 @@ class ObjectCache_WpObjectCache_Regular {
603
  * @return boolean
604
  */
605
  function _can_cache() {
 
 
 
 
 
 
 
 
 
606
  /**
607
  * Skip if disabled
608
  */
@@ -632,23 +814,31 @@ class ObjectCache_WpObjectCache_Regular {
632
  */
633
  function _check_can_cache_runtime( $group ) {
634
  //Need to be handled in wp admin as well as frontend
635
- if ( in_array( $group, array( 'transient', 'site-transient' ) ) )
636
  return true;
637
 
638
  if ( $this->_can_cache_dynamic != null )
639
  return $this->_can_cache_dynamic;
640
 
641
- if ( $this->_caching ) {
642
- if ( defined( 'WP_ADMIN' ) ) {
643
- $this->_can_cache_dynamic = false;
644
- $this->cache_reject_reason = 'WP_ADMIN defined';
645
- return $this->_can_cache_dynamic;
 
 
 
 
646
  }
647
  }
648
 
649
  return $this->_caching;
650
  }
651
 
 
 
 
 
652
  public function w3tc_footer_comment( $strings ) {
653
  if ( $this->_config->get_boolean( 'objectcache.debug' ) ) {
654
  $strings[] = "Object Cache debug info:";
@@ -665,22 +855,24 @@ class ObjectCache_WpObjectCache_Regular {
665
  $strings[] = sprintf( "%s%.4f", str_pad( 'Total time: ', 20 ), $this->time_total );
666
 
667
  $strings[] = "W3TC Object Cache info:";
668
- $strings[] = sprintf( "%s | %s | %s | %s | %s | %s",
669
  str_pad( '#', 5, ' ', STR_PAD_LEFT ),
670
- str_pad( 'Status', 15, ' ', STR_PAD_BOTH ),
671
- str_pad( 'Source', 15, ' ', STR_PAD_BOTH ),
672
  str_pad( 'Data size (b)', 13, ' ', STR_PAD_LEFT ),
673
  str_pad( 'Query time (s)', 14, ' ', STR_PAD_LEFT ),
674
- 'ID:Group' );
 
675
 
676
  foreach ( $this->debug_info as $index => $debug ) {
677
- $strings[] = sprintf( "%s | %s | %s | %s | %s | %s",
678
  str_pad( $index + 1, 5, ' ', STR_PAD_LEFT ),
679
- str_pad( ( $debug['cached'] ? 'cached' : 'not cached' ), 15, ' ', STR_PAD_BOTH ),
680
- str_pad( ( $debug['internal'] ? 'internal' : 'persistent' ), 15, ' ', STR_PAD_BOTH ),
681
  str_pad( $debug['data_size'], 13, ' ', STR_PAD_LEFT ),
682
  str_pad( round( $debug['time'], 4 ), 14, ' ', STR_PAD_LEFT ),
683
- sprintf( '%s:%s', $debug['id'], $debug['group'] ) );
 
684
  }
685
  } else {
686
  $reason = $this->get_reject_reason();
144
 
145
  $key = $this->_get_cache_key( $id, $group );
146
  $internal = isset( $this->cache[$key] );
147
+ $fallback_used = false;
148
 
149
  if ( $internal && !$force ) {
150
  $found = true;
154
  $this->_check_can_cache_runtime( $group ) ) {
155
  $cache = $this->_get_cache( null, $group );
156
  $v = $cache->get( $key );
157
+
158
+ /* for debugging
159
+ $a = $cache->_get_with_old_raw( $key );
160
+ $path = $cache->get_full_path( $key);
161
+ $returned = 'x ' . $path . ' ' .
162
+ (is_readable( $path ) ? ' readable ' : ' not-readable ') .
163
+ json_encode($a);
164
+ */
165
+
166
  if ( is_array( $v ) && $v['content'] != null ) {
167
  $found = true;
168
  $value = $v['content'];
169
+ } else {
170
+ $found = false;
171
  $value = false;
172
+ }
173
  } else {
174
+ $found = false;
175
  $value = false;
176
  }
177
 
183
  $value = clone $value;
184
  }
185
 
186
+ if ( !$found &&
187
+ $this->_is_transient_group( $group ) &&
188
+ $this->_config->get_boolean( 'objectcache.fallback_transients' ) ) {
189
+ $fallback_used = true;
190
+ $value = $this->_transient_fallback_get( $id, $group );
191
+ $found = ( $value !== false );
192
+ }
193
+
194
  $this->cache[$key] = $value;
195
  $this->cache_total++;
196
 
197
  if ( $value !== false ) {
 
198
  $this->cache_hits++;
199
  } else {
 
200
  $this->cache_misses++;
201
  }
202
 
211
  $group = 'default';
212
  }
213
 
214
+ if ( $fallback_used ) {
215
+ if ( !$found )
216
+ $returned = 'not in db';
217
+ else
218
+ $returned = 'from db fallback';
219
+ } else {
220
+ if ( !$found )
221
+ $returned = 'not in cache';
222
+ else {
223
+ if ( $internal )
224
+ $returned = 'from in-call cache';
225
+ else
226
+ $returned = 'from persistent cache';
227
+ }
228
+ }
229
+
230
  $this->debug_info[] = array(
231
  'id' => $id,
232
  'group' => $group,
233
+ 'operation' => 'get',
234
+ 'returned' => $returned,
235
  'data_size' => ( $value ? strlen( serialize( $value ) ) : '' ),
236
  'time' => $time
237
  );
257
  }
258
 
259
  $this->cache[$key] = $data;
260
+ $return = true;
261
+ $ext_return = false;
262
 
263
  if ( $this->_caching &&
264
  !in_array( $group, $this->nonpersistent_groups ) &&
276
  }
277
 
278
  $v = array( 'content' => $data );
279
+ $ext_return = $cache->set( $key, $v,
280
  ( $expire ? $expire : $this->_lifetime ) );
281
+ $return = $ext_return;
282
  }
283
 
284
+ if ( $this->_is_transient_group( $group ) &&
285
+ $this->_config->get_boolean( 'objectcache.fallback_transients' ) ) {
286
+ $this->_transient_fallback_set( $id, $data, $group, $expire );
287
+ }
288
+
289
+ if ( $this->_debug ) {
290
+ $this->debug_info[] = array(
291
+ 'id' => $id,
292
+ 'group' => $group,
293
+ 'operation' => 'set',
294
+ 'returned' => ( $ext_return ? 'put in cache' : 'discarded' ),
295
+ 'data_size' => ( $data ? strlen( serialize( $data ) ) : '' ),
296
+ 'time' => 0
297
+ );
298
+ }
299
+
300
+ return $return;
301
  }
302
 
303
  /**
314
  }
315
 
316
  $key = $this->_get_cache_key( $id, $group );
317
+ $return = true;
318
  unset( $this->cache[$key] );
319
 
320
  if ( $this->_caching && !in_array( $group, $this->nonpersistent_groups ) ) {
321
  $cache = $this->_get_cache( null, $group );
322
+ $return = $cache->delete( $key );
323
+ }
324
 
325
+ if ( $this->_is_transient_group( $group ) &&
326
+ $this->_config->get_boolean( 'objectcache.fallback_transients' ) ) {
327
+ $this->_transient_fallback_delete( $id, $group );
328
  }
329
 
330
+ if ( $this->_debug ) {
331
+ $this->debug_info[] = array(
332
+ 'id' => $id,
333
+ 'group' => $group,
334
+ 'operation' => 'delete',
335
+ 'returned' => ( $return ? 'deleted' : 'discarded' ),
336
+ 'data_size' => 0,
337
+ 'time' => 0
338
+ );
339
+ }
340
+
341
+ return $return;
342
  }
343
 
344
  /**
393
  *
394
  * @return boolean
395
  */
396
+ function flush( $reason = '' ) {
397
  $this->cache = array();
398
 
399
  global $w3_multisite_blogs;
410
  $cache->flush();
411
  }
412
 
413
+ if ( $this->_debug ) {
414
+ $this->debug_info[] = array(
415
+ 'id' => $id,
416
+ 'group' => $group,
417
+ 'operation' => 'flush',
418
+ 'returned' => $reason,
419
+ 'data_size' => 0,
420
+ 'time' => 0
421
+ );
422
+ }
423
+
424
  return true;
425
  }
426
 
504
  return $value;
505
  }
506
 
507
+ private function _transient_fallback_get( $transient, $group ) {
508
+ if ( $group == 'transient' ) {
509
+ $transient_option = '_transient_' . $transient;
510
+ if ( function_exists( 'wp_installing') && ! wp_installing() ) {
511
+ // If option is not in alloptions, it is not autoloaded and thus has a timeout
512
+ $alloptions = wp_load_alloptions();
513
+ if ( !isset( $alloptions[$transient_option] ) ) {
514
+ $transient_timeout = '_transient_timeout_' . $transient;
515
+ $timeout = get_option( $transient_timeout );
516
+ if ( false !== $timeout && $timeout < time() ) {
517
+ delete_option( $transient_option );
518
+ delete_option( $transient_timeout );
519
+ $value = false;
520
+ }
521
+ }
522
+ }
523
+
524
+ if ( ! isset( $value ) )
525
+ $value = get_option( $transient_option );
526
+ } elseif ( $group == 'site-transient' ) {
527
+ // Core transients that do not have a timeout. Listed here so querying timeouts can be avoided.
528
+ $no_timeout = array('update_core', 'update_plugins', 'update_themes');
529
+ $transient_option = '_site_transient_' . $transient;
530
+ if ( ! in_array( $transient, $no_timeout ) ) {
531
+ $transient_timeout = '_site_transient_timeout_' . $transient;
532
+ $timeout = get_site_option( $transient_timeout );
533
+ if ( false !== $timeout && $timeout < time() ) {
534
+ delete_site_option( $transient_option );
535
+ delete_site_option( $transient_timeout );
536
+ $value = false;
537
+ }
538
+ }
539
+
540
+ if ( ! isset( $value ) )
541
+ $value = get_site_option( $transient_option );
542
+ } else {
543
+ $value == false;
544
+ }
545
+
546
+ return $value;
547
+ }
548
+
549
+ private function _transient_fallback_delete( $transient, $group ) {
550
+ if ( $group == 'transient' ) {
551
+ $option_timeout = '_transient_timeout_' . $transient;
552
+ $option = '_transient_' . $transient;
553
+ $result = delete_option( $option );
554
+ if ( $result )
555
+ delete_option( $option_timeout );
556
+ } elseif ( $group == 'site-transient' ) {
557
+ $option_timeout = '_site_transient_timeout_' . $transient;
558
+ $option = '_site_transient_' . $transient;
559
+ $result = delete_site_option( $option );
560
+ if ( $result )
561
+ delete_site_option( $option_timeout );
562
+ }
563
+ }
564
+
565
+ private function _transient_fallback_set( $transient, $value, $group, $expiration ) {
566
+ if ( $group == 'transient' ) {
567
+ $transient_timeout = '_transient_timeout_' . $transient;
568
+ $transient_option = '_transient_' . $transient;
569
+ if ( false === get_option( $transient_option ) ) {
570
+ $autoload = 'yes';
571
+ if ( $expiration ) {
572
+ $autoload = 'no';
573
+ add_option( $transient_timeout, time() + $expiration, '', 'no' );
574
+ }
575
+ $result = add_option( $transient_option, $value, '', $autoload );
576
+ } else {
577
+ // If expiration is requested, but the transient has no timeout option,
578
+ // delete, then re-create transient rather than update.
579
+ $update = true;
580
+ if ( $expiration ) {
581
+ if ( false === get_option( $transient_timeout ) ) {
582
+ delete_option( $transient_option );
583
+ add_option( $transient_timeout, time() + $expiration, '', 'no' );
584
+ $result = add_option( $transient_option, $value, '', 'no' );
585
+ $update = false;
586
+ } else {
587
+ update_option( $transient_timeout, time() + $expiration );
588
+ }
589
+ }
590
+ if ( $update ) {
591
+ $result = update_option( $transient_option, $value );
592
+ }
593
+ }
594
+ } elseif ( $group == 'site-transient' ) {
595
+ $transient_timeout = '_site_transient_timeout_' . $transient;
596
+ $option = '_site_transient_' . $transient;
597
+ if ( false === get_site_option( $option ) ) {
598
+ if ( $expiration )
599
+ add_site_option( $transient_timeout, time() + $expiration );
600
+ $result = add_site_option( $option, $value );
601
+ } else {
602
+ if ( $expiration )
603
+ update_site_option( $transient_timeout, time() + $expiration );
604
+ $result = update_site_option( $option, $value );
605
+ }
606
+ }
607
+ }
608
+
609
  /**
610
  * Print Object Cache stats
611
  *
676
  if ( in_array( $group, $this->global_groups ) )
677
  $blog_id = 0;
678
 
679
+ return $blog_id . $group . $id;
 
 
 
 
 
 
 
 
 
680
  }
681
 
682
  public function get_usage_statistics_cache_config() {
688
  'servers' => $this->_config->get_array( 'objectcache.memcached.servers' ),
689
  'persistent' => $this->_config->get_boolean( 'objectcache.memcached.persistent' ),
690
  'aws_autodiscovery' => $this->_config->get_boolean( 'objectcache.memcached.aws_autodiscovery' ),
691
+ 'username' => $this->_config->get_string( 'objectcache.memcached.username' ),
692
+ 'password' => $this->_config->get_string( 'objectcache.memcached.password' )
693
  );
694
  break;
695
 
697
  $engineConfig = array(
698
  'servers' => $this->_config->get_array( 'objectcache.redis.servers' ),
699
  'persistent' => $this->_config->get_boolean( 'objectcache.redis.persistent' ),
700
+ 'dbid' => $this->_config->get_integer( 'objectcache.redis.dbid' ),
701
+ 'password' => $this->_config->get_string( 'objectcache.redis.password' )
702
  );
703
  break;
704
 
734
  'servers' => $this->_config->get_array( 'objectcache.memcached.servers' ),
735
  'persistent' => $this->_config->get_boolean( 'objectcache.memcached.persistent' ),
736
  'aws_autodiscovery' => $this->_config->get_boolean( 'objectcache.memcached.aws_autodiscovery' ),
737
+ 'username' => $this->_config->get_string( 'objectcache.memcached.username' ),
738
+ 'password' => $this->_config->get_string( 'objectcache.memcached.password' )
739
  );
740
  break;
741
 
743
  $engineConfig = array(
744
  'servers' => $this->_config->get_array( 'objectcache.redis.servers' ),
745
  'persistent' => $this->_config->get_boolean( 'objectcache.redis.persistent' ),
746
+ 'dbid' => $this->_config->get_integer( 'objectcache.redis.dbid' ),
747
+ 'password' => $this->_config->get_string( 'objectcache.redis.password' )
748
  );
749
  break;
750
 
776
  * @return boolean
777
  */
778
  function _can_cache() {
779
+ /**
780
+ * Don't cache in console mode
781
+ */
782
+ if ( PHP_SAPI === 'cli' ) {
783
+ $this->cache_reject_reason = 'Console mode';
784
+
785
+ return false;
786
+ }
787
+
788
  /**
789
  * Skip if disabled
790
  */
814
  */
815
  function _check_can_cache_runtime( $group ) {
816
  //Need to be handled in wp admin as well as frontend
817
+ if ( $this->_is_transient_group( $group ) )
818
  return true;
819
 
820
  if ( $this->_can_cache_dynamic != null )
821
  return $this->_can_cache_dynamic;
822
 
823
+ if ( $this->_config->get_boolean( 'objectcache.enabled_for_wp_admin' ) ) {
824
+ $this->_can_cache_dynamic = true;
825
+ } else {
826
+ if ( $this->_caching ) {
827
+ if ( defined( 'WP_ADMIN' ) ) {
828
+ $this->_can_cache_dynamic = false;
829
+ $this->cache_reject_reason = 'WP_ADMIN defined';
830
+ return $this->_can_cache_dynamic;
831
+ }
832
  }
833
  }
834
 
835
  return $this->_caching;
836
  }
837
 
838
+ private function _is_transient_group( $group ) {
839
+ return in_array( $group, array( 'transient', 'site-transient' ) ) ;
840
+ }
841
+
842
  public function w3tc_footer_comment( $strings ) {
843
  if ( $this->_config->get_boolean( 'objectcache.debug' ) ) {
844
  $strings[] = "Object Cache debug info:";
855
  $strings[] = sprintf( "%s%.4f", str_pad( 'Total time: ', 20 ), $this->time_total );
856
 
857
  $strings[] = "W3TC Object Cache info:";
858
+ $strings[] = sprintf( "%s | %s | %s | %s | %s | %s | %s",
859
  str_pad( '#', 5, ' ', STR_PAD_LEFT ),
860
+ str_pad( 'Op', 5, ' ', STR_PAD_BOTH ),
861
+ str_pad( 'Returned', 25, ' ', STR_PAD_BOTH ),
862
  str_pad( 'Data size (b)', 13, ' ', STR_PAD_LEFT ),
863
  str_pad( 'Query time (s)', 14, ' ', STR_PAD_LEFT ),
864
+ str_pad( 'Group', 15, ' ', STR_PAD_LEFT ),
865
+ 'ID' );
866
 
867
  foreach ( $this->debug_info as $index => $debug ) {
868
+ $strings[] = sprintf( "%s | %s | %s | %s | %s | %s | %s",
869
  str_pad( $index + 1, 5, ' ', STR_PAD_LEFT ),
870
+ str_pad( $debug['operation'], 5, ' ', STR_PAD_BOTH ),
871
+ str_pad( $debug['returned'], 25, ' ', STR_PAD_BOTH ),
872
  str_pad( $debug['data_size'], 13, ' ', STR_PAD_LEFT ),
873
  str_pad( round( $debug['time'], 4 ), 14, ' ', STR_PAD_LEFT ),
874
+ str_pad( $debug['group'], 15, ' ', STR_PAD_LEFT ),
875
+ $debug['id'] );
876
  }
877
  } else {
878
  $reason = $this->get_reject_reason();
PgCache_ContentGrabber.php CHANGED
@@ -237,7 +237,7 @@ class PgCache_ContentGrabber {
237
  if ( !$this->_set_extract_page_key( $mobile_group, $referrer_group,
238
  $encryption, $compression, '', $with_filter ) ) {
239
  $data = null;
240
- } else {
241
  $data = $cache->get_with_old( $this->_page_key, $group );
242
  list( $data, $this->_old_exists ) = $data;
243
  }
@@ -246,11 +246,11 @@ class PgCache_ContentGrabber {
246
  * Try to get uncompressed version of cache
247
  */
248
  if ( $compression && !$data ) {
249
- if ( $this->_set_extract_page_key( $mobile_group,
250
  $referrer_group, $encryption, false, '', $with_filter ) ) {
251
  $data = null;
252
  } else {
253
- $data = $cache->get_with_old( $this->_page_key );
254
  list( $data, $this->_old_exists ) = $data;
255
  $compression = false;
256
  }
@@ -309,7 +309,6 @@ class PgCache_ContentGrabber {
309
  $headers = $data['headers'];
310
  $content = $data['content'];
311
  $has_dynamic = isset( $data['has_dynamic'] ) && $data['has_dynamic'];
312
-
313
  $etag = md5( $content );
314
 
315
  if ( $has_dynamic ) {
@@ -370,15 +369,32 @@ class PgCache_ContentGrabber {
370
  if ( $can_cache ) {
371
  $buffer = $this->_maybe_save_cached_result( $buffer, $has_dynamic );
372
  } else {
 
 
 
 
 
 
 
 
 
 
373
  if ( $this->cache_reject_reason ) {
374
  if ( $this->_old_exists ) {
375
- /**
376
- *
377
- *
378
- * @var W3_Cache_File_Generic $cache
379
- */
380
  $cache = $this->_get_cache();
381
- $cache->hard_delete( $this->_page_key );
 
 
 
 
 
 
 
 
 
 
 
 
382
  }
383
  }
384
  }
@@ -406,7 +422,7 @@ class PgCache_ContentGrabber {
406
  *
407
  * @return void
408
  */
409
- function shutdown() {
410
  $compression = $this->_get_compression();
411
 
412
  // Parse dynamic content
@@ -421,7 +437,7 @@ class PgCache_ContentGrabber {
421
  *
422
  * @return boolean
423
  */
424
- function _can_cache() {
425
  /**
426
  * Don't cache in console mode
427
  */
@@ -440,6 +456,12 @@ class PgCache_ContentGrabber {
440
  return false;
441
  }
442
 
 
 
 
 
 
 
443
  /**
444
  * Skip if posting
445
  */
@@ -522,7 +544,7 @@ class PgCache_ContentGrabber {
522
  * @param string $buffer
523
  * @return boolean
524
  */
525
- function _can_cache2( $buffer ) {
526
  /**
527
  * Skip if caching is disabled
528
  */
@@ -613,8 +635,8 @@ class PgCache_ContentGrabber {
613
  'servers' => $this->_config->get_array( 'pgcache.memcached.servers' ),
614
  'persistent' => $this->_config->get_boolean( 'pgcache.memcached.persistent' ),
615
  'aws_autodiscovery' => $this->_config->get_boolean( 'pgcache.memcached.aws_autodiscovery' ),
616
- 'username' => $this->_config->get_boolean( 'pgcache.memcached.username' ),
617
- 'password' => $this->_config->get_boolean( 'pgcache.memcached.password' )
618
  );
619
  break;
620
 
@@ -622,8 +644,8 @@ class PgCache_ContentGrabber {
622
  $engineConfig = array(
623
  'servers' => $this->_config->get_array( 'pgcache.redis.servers' ),
624
  'persistent' => $this->_config->get_boolean( 'pgcache.redis.persistent' ),
625
- 'dbid' => $this->_config->get_boolean( 'pgcache.redis.dbid' ),
626
- 'password' => $this->_config->get_boolean( 'pgcache.redis.password' )
627
  );
628
  break;
629
 
@@ -656,8 +678,8 @@ class PgCache_ContentGrabber {
656
  'servers' => $this->_config->get_array( 'pgcache.memcached.servers' ),
657
  'persistent' => $this->_config->get_boolean( 'pgcache.memcached.persistent' ),
658
  'aws_autodiscovery' => $this->_config->get_boolean( 'pgcache.memcached.aws_autodiscovery' ),
659
- 'username' => $this->_config->get_boolean( 'pgcache.memcached.username' ),
660
- 'password' => $this->_config->get_boolean( 'pgcache.memcached.password' )
661
  );
662
  break;
663
 
@@ -665,8 +687,8 @@ class PgCache_ContentGrabber {
665
  $engineConfig = array(
666
  'servers' => $this->_config->get_array( 'pgcache.redis.servers' ),
667
  'persistent' => $this->_config->get_boolean( 'pgcache.redis.persistent' ),
668
- 'dbid' => $this->_config->get_boolean( 'pgcache.redis.dbid' ),
669
- 'password' => $this->_config->get_boolean( 'pgcache.redis.password' )
670
  );
671
  break;
672
 
@@ -944,7 +966,9 @@ class PgCache_ContentGrabber {
944
  false
945
  );
946
 
947
- if ( $this->_config->get_boolean( 'browsercache.enabled' ) && $this->_config->get_boolean( 'browsercache.html.compression' ) && function_exists( 'gzencode' ) ) {
 
 
948
  $compressions[] = 'gzip';
949
  }
950
 
@@ -957,7 +981,8 @@ class PgCache_ContentGrabber {
957
  * @return array
958
  */
959
  function _get_response_headers() {
960
- $headers = array();
 
961
 
962
  if ( function_exists( 'headers_list' ) ) {
963
  $headers_list = headers_list();
@@ -966,17 +991,24 @@ class PgCache_ContentGrabber {
966
  $pos = strpos( $header, ':' );
967
  if ( $pos ) {
968
  $header_name = substr( $header, 0, $pos );
969
- $header_value = substr( $header, $pos+1 );
970
  } else {
971
  $header_name = $header;
972
  $header_value = '';
973
  }
974
- $headers[$header_name] = $header_value;
 
 
 
 
975
  }
976
  }
977
  }
978
 
979
- return $headers;
 
 
 
980
  }
981
 
982
  /**
@@ -1010,13 +1042,34 @@ class PgCache_ContentGrabber {
1010
  $this->_config->get_array( 'pgcache.cache.headers' )
1011
  );
1012
 
1013
- if ( function_exists( 'http_response_code' ) ) // php5.3 compatibility
1014
  $data_headers['Status-Code'] = http_response_code();
 
 
 
 
 
 
 
 
 
 
 
 
 
1015
 
1016
- foreach ( $response_headers as $header_name => $header_value ) {
1017
  foreach ( $cache_headers as $cache_header_name ) {
1018
  if ( strcasecmp( $header_name, $cache_header_name ) == 0 ) {
1019
- $data_headers[$header_name] = $header_value;
 
 
 
 
 
 
 
 
 
1020
  }
1021
  }
1022
  }
@@ -1160,11 +1213,13 @@ class PgCache_ContentGrabber {
1160
 
1161
  $headers = $this->_get_response_headers();
1162
 
1163
- if ( count( $headers ) ) {
1164
  $strings[] = "Header info:";
1165
 
1166
- foreach ( $headers as $header_name => $header_value ) {
1167
- $strings[] = sprintf( "%s%s", str_pad( $header_name . ': ', 20 ), Util_Content::escape_comment( $header_value ) );
 
 
1168
  }
1169
  }
1170
  }
@@ -1182,17 +1237,28 @@ class PgCache_ContentGrabber {
1182
  if ( headers_sent() )
1183
  return false;
1184
 
1185
- // status first
1186
- if ( isset( $headers['Status'] ) )
1187
- @header( $headers['Status'] );
1188
- else if ( isset( $headers['Status-Code'] ) &&
1189
- function_exists( 'http_response_code' ) ) // php5.3 compatibility)
1190
- @http_response_code( $headers['Status-Code'] );
 
 
 
 
 
1191
 
1192
- foreach ( $headers as $name => $value ) {
1193
- if ( $name != 'Status' && $name != 'Status-Code' )
1194
- @header( $name . ': ' . $value );
 
 
 
 
 
1195
  }
 
1196
 
1197
  return true;
1198
  }
@@ -1215,23 +1281,19 @@ class PgCache_ContentGrabber {
1215
  $bc_lifetime = $this->_config->get_integer(
1216
  'browsercache.html.lifetime' );
1217
 
1218
- $expires = ( is_null( $time )? $curr_time: $time ) + $bc_lifetime;
1219
  $max_age = ( $expires > $curr_time ? $expires - $curr_time : 0 );
1220
 
1221
  if ( $is_404 ) {
1222
  /**
1223
  * Add 404 header
1224
  */
1225
- $headers = array_merge( $headers, array(
1226
- 'Status' => 'HTTP/1.1 404 Not Found'
1227
- ) );
1228
  } elseif ( ( !is_null( $time ) && $this->_check_modified_since( $time ) ) || $this->_check_match( $etag ) ) {
1229
  /**
1230
  * Add 304 header
1231
  */
1232
- $headers = array_merge( $headers, array(
1233
- 'Status' => 'HTTP/1.1 304 Not Modified'
1234
- ) );
1235
 
1236
  /**
1237
  * Don't send content if it isn't modified
@@ -1242,89 +1304,88 @@ class PgCache_ContentGrabber {
1242
  if ( $this->_config->get_boolean( 'browsercache.enabled' ) ) {
1243
 
1244
  if ( $this->_config->get_boolean( 'browsercache.html.last_modified' ) ) {
1245
- $headers = array_merge( $headers, array(
1246
- 'Last-Modified' => Util_Content::http_date( $time )
1247
- ) );
1248
  }
1249
 
1250
  if ( $this->_config->get_boolean( 'browsercache.html.expires' ) ) {
1251
- $headers = array_merge( $headers, array(
1252
- 'Expires' => Util_Content::http_date( $expires )
1253
- ) );
1254
  }
1255
 
1256
  if ( $this->_config->get_boolean( 'browsercache.html.cache.control' ) ) {
1257
  switch ( $this->_config->get_string( 'browsercache.html.cache.policy' ) ) {
1258
  case 'cache':
1259
- $headers = array_merge( $headers, array(
1260
- 'Pragma' => 'public',
1261
- 'Cache-Control' => 'public'
1262
- ) );
1263
  break;
1264
 
1265
  case 'cache_public_maxage':
1266
- $headers = array_merge( $headers, array(
1267
- 'Pragma' => 'public',
1268
- 'Cache-Control' => sprintf( 'max-age=%d, public', $max_age )
1269
- ) );
1270
  break;
1271
 
1272
  case 'cache_validation':
1273
- $headers = array_merge( $headers, array(
1274
- 'Pragma' => 'public',
1275
- 'Cache-Control' => 'public, must-revalidate, proxy-revalidate'
1276
- ) );
1277
  break;
1278
 
1279
  case 'cache_noproxy':
1280
- $headers = array_merge( $headers, array(
1281
- 'Pragma' => 'public',
1282
- 'Cache-Control' => 'private, must-revalidate'
1283
- ) );
1284
  break;
1285
 
1286
  case 'cache_maxage':
1287
- $headers = array_merge( $headers, array(
1288
- 'Pragma' => 'public',
1289
- 'Cache-Control' => sprintf( 'max-age=%d, public, must-revalidate, proxy-revalidate', $max_age )
1290
- ) );
1291
  break;
1292
 
1293
  case 'no_cache':
1294
- $headers = array_merge( $headers, array(
1295
- 'Pragma' => 'no-cache',
1296
- 'Cache-Control' => 'max-age=0, private, no-store, no-cache, must-revalidate'
1297
- ) );
1298
  break;
1299
  }
1300
  }
1301
 
1302
  if ( $this->_config->get_boolean( 'browsercache.html.etag' ) ) {
1303
- $headers = array_merge( $headers, array(
1304
- 'ETag' => '"' . $etag . '"'
1305
- ) );
1306
  }
 
 
1307
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1308
  if ( $this->_config->get_boolean( 'browsercache.html.w3tc' ) ) {
1309
- $headers = array_merge( $headers, array(
1310
- 'X-Powered-By' => Util_Environment::w3tc_header()
1311
- ) );
1312
  }
1313
  }
1314
 
1315
- $vary ='';
1316
  //compressed && UAG
1317
  if ( $compression && $this->_get_mobile_group() ) {
1318
  $vary = 'Accept-Encoding,User-Agent,Cookie';
1319
- $headers = array_merge( $headers, array(
1320
- 'Content-Encoding' => $compression
1321
- ) );
1322
  //compressed
1323
  } elseif ( $compression ) {
1324
  $vary = 'Accept-Encoding';
1325
- $headers = array_merge( $headers, array(
1326
- 'Content-Encoding' => $compression
1327
- ) );
1328
  //uncompressed && UAG
1329
  } elseif ( $this->_get_mobile_group() ) {
1330
  $vary = 'User-Agent,Cookie';
@@ -1342,28 +1403,17 @@ class PgCache_ContentGrabber {
1342
  * Add vary header
1343
  */
1344
  if ( $vary )
1345
- $headers = array_merge( $headers, array(
1346
- 'Vary' => $vary ) );
1347
 
1348
  /**
1349
  * Disable caching for preview mode
1350
  */
1351
  if ( Util_Environment::is_preview_mode() ) {
1352
- $headers = array_merge( $headers, array(
1353
- 'Pragma' => 'private',
1354
- 'Cache-Control' => 'private'
1355
- ) );
1356
  }
1357
 
1358
- /**
1359
- * Send headers to client
1360
- */
1361
- $result = $this->_headers( $headers );
1362
-
1363
- if ( $exit )
1364
- exit();
1365
-
1366
- return $result;
1367
  }
1368
 
1369
  /**
@@ -1614,9 +1664,9 @@ class PgCache_ContentGrabber {
1614
  $content_type = '';
1615
  $is_404 = ( function_exists( 'is_404' ) ? is_404() : false );
1616
  $response_headers = $this->_get_response_headers();
1617
- $headers = $this->_get_cached_headers( $response_headers );
1618
 
1619
- if ( !empty( $response_headers['Content-Encoding'] ) ) {
1620
  $this->cache_reject_reason = 'Response is compressed';
1621
  return $buffer;
1622
  }
@@ -1624,7 +1674,7 @@ class PgCache_ContentGrabber {
1624
  if ( $this->_enhanced_mode ) {
1625
  // redirect issued, if we have some old cache entries
1626
  // they will be turned into fresh files and catch further requests
1627
- if ( isset( $response_headers['Location'] ) ) {
1628
  foreach ( $compressions_to_store as $_compression ) {
1629
  $_page_key = $this->_get_page_key( $mobile_group,
1630
  $referrer_group, $encryption, $_compression,
@@ -1643,8 +1693,8 @@ class PgCache_ContentGrabber {
1643
  '_check_rules_present'
1644
  ) );
1645
 
1646
- if ( isset( $headers['Content-Type'] ) )
1647
- $content_type = $headers['Content-Type'];
1648
  }
1649
 
1650
  $time = time();
237
  if ( !$this->_set_extract_page_key( $mobile_group, $referrer_group,
238
  $encryption, $compression, '', $with_filter ) ) {
239
  $data = null;
240
+ } else {
241
  $data = $cache->get_with_old( $this->_page_key, $group );
242
  list( $data, $this->_old_exists ) = $data;
243
  }
246
  * Try to get uncompressed version of cache
247
  */
248
  if ( $compression && !$data ) {
249
+ if ( !$this->_set_extract_page_key( $mobile_group,
250
  $referrer_group, $encryption, false, '', $with_filter ) ) {
251
  $data = null;
252
  } else {
253
+ $data = $cache->get_with_old( $this->_page_key, $group );
254
  list( $data, $this->_old_exists ) = $data;
255
  $compression = false;
256
  }
309
  $headers = $data['headers'];
310
  $content = $data['content'];
311
  $has_dynamic = isset( $data['has_dynamic'] ) && $data['has_dynamic'];
 
312
  $etag = md5( $content );
313
 
314
  if ( $has_dynamic ) {
369
  if ( $can_cache ) {
370
  $buffer = $this->_maybe_save_cached_result( $buffer, $has_dynamic );
371
  } else {
372
+ if ( $has_dynamic ) {
373
+ // send common headers since output will be compressed
374
+ $compression_header = $this->_get_compression();
375
+ if ( defined( 'W3TC_PAGECACHE_OUTPUT_COMPRESSION_OFF' ) )
376
+ $compression_header = false;
377
+ $headers = $this->_get_common_headers( $compression_header );
378
+ $this->_headers( $headers );
379
+ }
380
+
381
+ // remove cached entries if its not cached anymore
382
  if ( $this->cache_reject_reason ) {
383
  if ( $this->_old_exists ) {
 
 
 
 
 
384
  $cache = $this->_get_cache();
385
+
386
+ $mobile_group = $this->_get_mobile_group();
387
+ $referrer_group = $this->_get_referrer_group();
388
+ $encryption = $this->_get_encryption();
389
+ $compressions_to_store = $this->_get_compressions();
390
+ $content_type = '';
391
+
392
+ foreach ( $compressions_to_store as $_compression ) {
393
+ $_page_key = $this->_get_page_key( $mobile_group,
394
+ $referrer_group, $encryption, $_compression,
395
+ $content_type );
396
+ $cache->hard_delete( $_page_key );
397
+ }
398
  }
399
  }
400
  }
422
  *
423
  * @return void
424
  */
425
+ public function shutdown() {
426
  $compression = $this->_get_compression();
427
 
428
  // Parse dynamic content
437
  *
438
  * @return boolean
439
  */
440
+ private function _can_cache() {
441
  /**
442
  * Don't cache in console mode
443
  */
456
  return false;
457
  }
458
 
459
+ if ( !$this->_config->get_boolean('pgcache.cache.ssl') && Util_Environment::is_https() ) {
460
+ $this->cache_reject_reason = 'SSL caching disabled';
461
+
462
+ return false;
463
+ }
464
+
465
  /**
466
  * Skip if posting
467
  */
544
  * @param string $buffer
545
  * @return boolean
546
  */
547
+ private function _can_cache2( $buffer ) {
548
  /**
549
  * Skip if caching is disabled
550
  */
635
  'servers' => $this->_config->get_array( 'pgcache.memcached.servers' ),
636
  'persistent' => $this->_config->get_boolean( 'pgcache.memcached.persistent' ),
637
  'aws_autodiscovery' => $this->_config->get_boolean( 'pgcache.memcached.aws_autodiscovery' ),
638
+ 'username' => $this->_config->get_string( 'pgcache.memcached.username' ),
639
+ 'password' => $this->_config->get_string( 'pgcache.memcached.password' )
640
  );
641
  break;
642
 
644
  $engineConfig = array(
645
  'servers' => $this->_config->get_array( 'pgcache.redis.servers' ),
646
  'persistent' => $this->_config->get_boolean( 'pgcache.redis.persistent' ),
647
+ 'dbid' => $this->_config->get_integer( 'pgcache.redis.dbid' ),
648
+ 'password' => $this->_config->get_string( 'pgcache.redis.password' )
649
  );
650
  break;
651
 
678
  'servers' => $this->_config->get_array( 'pgcache.memcached.servers' ),
679
  'persistent' => $this->_config->get_boolean( 'pgcache.memcached.persistent' ),
680
  'aws_autodiscovery' => $this->_config->get_boolean( 'pgcache.memcached.aws_autodiscovery' ),
681
+ 'username' => $this->_config->get_string( 'pgcache.memcached.username' ),
682
+ 'password' => $this->_config->get_string( 'pgcache.memcached.password' )
683
  );
684
  break;
685
 
687
  $engineConfig = array(
688
  'servers' => $this->_config->get_array( 'pgcache.redis.servers' ),
689
  'persistent' => $this->_config->get_boolean( 'pgcache.redis.persistent' ),
690
+ 'dbid' => $this->_config->get_integer( 'pgcache.redis.dbid' ),
691
+ 'password' => $this->_config->get_string( 'pgcache.redis.password' )
692
  );
693
  break;
694
 
966
  false
967
  );
968
 
969
+ if ( $this->_config->get_boolean( 'browsercache.enabled' ) &&
970
+ $this->_config->get_boolean( 'browsercache.html.compression' ) &&
971
+ function_exists( 'gzencode' ) ) {
972
  $compressions[] = 'gzip';
973
  }
974
 
981
  * @return array
982
  */
983
  function _get_response_headers() {
984
+ $headers_kv = array();
985
+ $headers_plain = array();
986
 
987
  if ( function_exists( 'headers_list' ) ) {
988
  $headers_list = headers_list();
991
  $pos = strpos( $header, ':' );
992
  if ( $pos ) {
993
  $header_name = substr( $header, 0, $pos );
994
+ $header_value = substr( $header, $pos + 1 );
995
  } else {
996
  $header_name = $header;
997
  $header_value = '';
998
  }
999
+ $headers_kv[$header_name] = $header_value;
1000
+ $headers_plain[] = array(
1001
+ 'name' => $header_name,
1002
+ 'value' => $header_value
1003
+ );
1004
  }
1005
  }
1006
  }
1007
 
1008
+ return array(
1009
+ 'kv' => $headers_kv,
1010
+ 'plain' => $headers_plain
1011
+ );
1012
  }
1013
 
1014
  /**
1042
  $this->_config->get_array( 'pgcache.cache.headers' )
1043
  );
1044
 
1045
+ if ( function_exists( 'http_response_code' ) ) { // php5.3 compatibility
1046
  $data_headers['Status-Code'] = http_response_code();
1047
+ }
1048
+
1049
+ $repeating_headers = array(
1050
+ 'link',
1051
+ 'cookie',
1052
+ 'set-cookie'
1053
+ );
1054
+ $repeating_headers = apply_filters( 'w3tc_repeating_headers',
1055
+ $repeating_headers );
1056
+
1057
+ foreach ( $response_headers as $i ) {
1058
+ $header_name = $i['name'];
1059
+ $header_value = $i['value'];
1060
 
 
1061
  foreach ( $cache_headers as $cache_header_name ) {
1062
  if ( strcasecmp( $header_name, $cache_header_name ) == 0 ) {
1063
+ $header_name_lo = strtolower( $header_name );
1064
+ if ( in_array($header_name_lo, $repeating_headers) ) {
1065
+ // headers may repeat
1066
+ $data_headers[] = array(
1067
+ 'n' => $header_name,
1068
+ 'v' => $header_value
1069
+ );
1070
+ } else {
1071
+ $data_headers[$header_name] = $header_value;
1072
+ }
1073
  }
1074
  }
1075
  }
1213
 
1214
  $headers = $this->_get_response_headers();
1215
 
1216
+ if ( count( $headers['plain'] ) ) {
1217
  $strings[] = "Header info:";
1218
 
1219
+ foreach ( $headers['plain'] as $i ) {
1220
+ $strings[] = sprintf( "%s%s",
1221
+ str_pad( $i['name'] . ': ', 20 ),
1222
+ Util_Content::escape_comment( $i['value'] ) );
1223
  }
1224
  }
1225
  }
1237
  if ( headers_sent() )
1238
  return false;
1239
 
1240
+ $repeating = array();
1241
+ // headers are sent as name->value and array(n=>, v=>)
1242
+ // to support repeating headers
1243
+ foreach ( $headers as $name0 => $value0 ) {
1244
+ if ( isset( $value0['n'] ) ) {
1245
+ $name = $value0['n'];
1246
+ $value = $value0['v'];
1247
+ } else {
1248
+ $name = $name0;
1249
+ $value = $value0;
1250
+ }
1251
 
1252
+ if ( $name == 'Status' ) {
1253
+ @header( $headers['Status'] );
1254
+ } elseif ( $name == 'Status-Code' ) {
1255
+ if ( function_exists( 'http_response_code' ) ) // php5.3 compatibility)
1256
+ @http_response_code( $headers['Status-Code'] );
1257
+ } else {
1258
+ @header( $name . ': ' . $value, !isset( $repeating[$name] ) );
1259
+ $repeating[$name] = true;
1260
  }
1261
+ }
1262
 
1263
  return true;
1264
  }
1281
  $bc_lifetime = $this->_config->get_integer(
1282
  'browsercache.html.lifetime' );
1283
 
1284
+ $expires = ( is_null( $time ) ? $curr_time : $time ) + $bc_lifetime;
1285
  $max_age = ( $expires > $curr_time ? $expires - $curr_time : 0 );
1286
 
1287
  if ( $is_404 ) {
1288
  /**
1289
  * Add 404 header
1290
  */
1291
+ $headers['Status'] = 'HTTP/1.1 404 Not Found';
 
 
1292
  } elseif ( ( !is_null( $time ) && $this->_check_modified_since( $time ) ) || $this->_check_match( $etag ) ) {
1293
  /**
1294
  * Add 304 header
1295
  */
1296
+ $headers['Status'] = 'HTTP/1.1 304 Not Modified';
 
 
1297
 
1298
  /**
1299
  * Don't send content if it isn't modified
1304
  if ( $this->_config->get_boolean( 'browsercache.enabled' ) ) {
1305
 
1306
  if ( $this->_config->get_boolean( 'browsercache.html.last_modified' ) ) {
1307
+ $headers['Last-Modified'] = Util_Content::http_date( $time );
 
 
1308
  }
1309
 
1310
  if ( $this->_config->get_boolean( 'browsercache.html.expires' ) ) {
1311
+ $headers['Expires'] = Util_Content::http_date( $expires );
 
 
1312
  }
1313
 
1314
  if ( $this->_config->get_boolean( 'browsercache.html.cache.control' ) ) {
1315
  switch ( $this->_config->get_string( 'browsercache.html.cache.policy' ) ) {
1316
  case 'cache':
1317
+ $headers['Pragma'] = 'public';
1318
+ $headers['Cache-Control'] = 'public';
 
 
1319
  break;
1320
 
1321
  case 'cache_public_maxage':
1322
+ $headers['Pragma'] = 'public';
1323
+ $headers['Cache-Control'] = sprintf( 'max-age=%d, public', $max_age );
 
 
1324
  break;
1325
 
1326
  case 'cache_validation':
1327
+ $headers['Pragma'] = 'public';
1328
+ $headers['Cache-Control'] = 'public, must-revalidate, proxy-revalidate';
 
 
1329
  break;
1330
 
1331
  case 'cache_noproxy':
1332
+ $headers['Pragma'] = 'public';
1333
+ $headers['Cache-Control'] = 'private, must-revalidate';
 
 
1334
  break;
1335
 
1336
  case 'cache_maxage':
1337
+ $headers['Pragma'] = 'public';
1338
+ $headers['Cache-Control'] = sprintf( 'max-age=%d, public, must-revalidate, proxy-revalidate', $max_age );
 
 
1339
  break;
1340
 
1341
  case 'no_cache':
1342
+ $headers['Pragma'] = 'no-cache';
1343
+ $headers['Cache-Control'] = 'max-age=0, private, no-store, no-cache, must-revalidate';
 
 
1344
  break;
1345
  }
1346
  }
1347
 
1348
  if ( $this->_config->get_boolean( 'browsercache.html.etag' ) ) {
1349
+ $headers['ETag'] = '"' . $etag . '"';
 
 
1350
  }
1351
+ }
1352
+
1353
 
1354
+ $headers = array_merge( $headers,
1355
+ $this->_get_common_headers( $compression ) );
1356
+
1357
+ /**
1358
+ * Send headers to client
1359
+ */
1360
+ $result = $this->_headers( $headers );
1361
+
1362
+ if ( $exit )
1363
+ exit();
1364
+
1365
+ return $result;
1366
+ }
1367
+
1368
+ /**
1369
+ * Returns headers to send regardless is page caching is active
1370
+ */
1371
+ function _get_common_headers( $compression ) {
1372
+ $headers = array();
1373
+
1374
+ if ( $this->_config->get_boolean( 'browsercache.enabled' ) ) {
1375
  if ( $this->_config->get_boolean( 'browsercache.html.w3tc' ) ) {
1376
+ $headers['X-Powered-By'] = Util_Environment::w3tc_header();
 
 
1377
  }
1378
  }
1379
 
1380
+ $vary = '';
1381
  //compressed && UAG
1382
  if ( $compression && $this->_get_mobile_group() ) {
1383
  $vary = 'Accept-Encoding,User-Agent,Cookie';
1384
+ $headers['Content-Encoding'] = $compression;
 
 
1385
  //compressed
1386
  } elseif ( $compression ) {
1387
  $vary = 'Accept-Encoding';
1388
+ $headers['Content-Encoding'] = $compression;
 
 
1389
  //uncompressed && UAG
1390
  } elseif ( $this->_get_mobile_group() ) {
1391
  $vary = 'User-Agent,Cookie';
1403
  * Add vary header
1404
  */
1405
  if ( $vary )
1406
+ $headers['Vary'] = $vary;
 
1407
 
1408
  /**
1409
  * Disable caching for preview mode
1410
  */
1411
  if ( Util_Environment::is_preview_mode() ) {
1412
+ $headers['Pragma'] = 'private';
1413
+ $headers['Cache-Control'] = 'private';
 
 
1414
  }
1415
 
1416
+ return $headers;
 
 
 
 
 
 
 
 
1417
  }
1418
 
1419
  /**
1664
  $content_type = '';
1665
  $is_404 = ( function_exists( 'is_404' ) ? is_404() : false );
1666
  $response_headers = $this->_get_response_headers();
1667
+ $headers = $this->_get_cached_headers( $response_headers['plain'] );
1668
 
1669
+ if ( !empty( $response_headers['kv']['Content-Encoding'] ) ) {
1670
  $this->cache_reject_reason = 'Response is compressed';
1671
  return $buffer;
1672
  }
1674
  if ( $this->_enhanced_mode ) {
1675
  // redirect issued, if we have some old cache entries
1676
  // they will be turned into fresh files and catch further requests
1677
+ if ( isset( $response_headers['kv']['Location'] ) ) {
1678
  foreach ( $compressions_to_store as $_compression ) {
1679
  $_page_key = $this->_get_page_key( $mobile_group,
1680
  $referrer_group, $encryption, $_compression,
1693
  '_check_rules_present'
1694
  ) );
1695
 
1696
+ if ( isset( $response_headers['kv']['Content-Type'] ) )
1697
+ $content_type = $response_headers['kv']['Content-Type'];
1698
  }
1699
 
1700
  $time = time();
PgCache_Plugin.php CHANGED
@@ -248,7 +248,7 @@ class PgCache_Plugin {
248
  'id' => 'w3tc_pgcache_flush_post',
249
  'parent' => 'w3tc_flush',
250
  'title' => __( 'Page Cache: Current Page', 'w3-total-cache' ),
251
- 'href' => wp_nonce_url( network_admin_url(
252
  'admin.php?page=w3tc_dashboard&amp;w3tc_flush_post&amp;post_id=' .
253
  Util_Environment::detect_post_id() ), 'w3tc' )
254
  );
248
  'id' => 'w3tc_pgcache_flush_post',
249
  'parent' => 'w3tc_flush',
250
  'title' => __( 'Page Cache: Current Page', 'w3-total-cache' ),
251
+ 'href' => wp_nonce_url( admin_url(
252
  'admin.php?page=w3tc_dashboard&amp;w3tc_flush_post&amp;post_id=' .
253
  Util_Environment::detect_post_id() ), 'w3tc' )
254
  );
PgCache_Plugin_Admin.php CHANGED
@@ -107,11 +107,13 @@ class PgCache_Plugin_Admin {
107
  if ( $start == 0 ) {
108
  $crons = _get_cron_array();
109
 
110
- foreach ( $crons as $timestamp => $hooks ) {
111
- foreach ( $hooks as $hook => $keys ) {
112
- foreach ( $keys as $key => $data ) {
113
- if ( $hook == 'w3_pgcache_prime' && count( $data['args'] ) ) {
114
- return;
 
 
115
  }
116
  }
117
  }
@@ -144,10 +146,10 @@ class PgCache_Plugin_Admin {
144
 
145
 
146
 
147
- // use empty user-agent since by default we use W3TC-powered by
148
  // which blocks caching
149
  foreach ( $queue as $url )
150
- Util_Http::get( $url, array( 'user-agent' => '' ) );
151
  }
152
 
153
  /**
@@ -221,7 +223,7 @@ class PgCache_Plugin_Admin {
221
 
222
  // Make HTTP requests and prime cache
223
  foreach ( $post_urls as $url ) {
224
- $result = Util_Http::get( $url, array( 'user-agent' => '' ) );
225
  if ( is_wp_error( $result ) )
226
  return false;
227
  }
@@ -271,16 +273,15 @@ class PgCache_Plugin_Admin {
271
  if ( $this->_config->get_string( 'pgcache.engine' ) == 'memcached' ) {
272
  $summary['memcached_servers']['pgcache'] = array(
273
  'servers' => $this->_config->get_array( 'pgcache.memcached.servers' ),
274
- 'username' => $this->_config->get_boolean( 'pgcache.memcached.username' ),
275
- 'password' => $this->_config->get_boolean( 'pgcache.memcached.password' ),
276
  'name' => __( 'Page Cache', 'w3-total-cache' )
277
  );
278
  } elseif ( $this->_config->get_string( 'pgcache.engine' ) == 'redis' ) {
279
  $summary['redis_servers']['pgcache'] = array(
280
  'servers' => $this->_config->get_array( 'pgcache.redis.servers' ),
281
- 'username' => $this->_config->get_boolean( 'pgcache.redis.username' ),
282
- 'dbid' => $this->_config->get_boolean( 'pgcache.redis.dbid' ),
283
- 'password' => $this->_config->get_boolean( 'pgcache.redis.password' ),
284
  'name' => __( 'Page Cache', 'w3-total-cache' )
285
  );
286
  }
107
  if ( $start == 0 ) {
108
  $crons = _get_cron_array();
109
 
110
+ if ( is_array( $crons ) ) {
111
+ foreach ( $crons as $timestamp => $hooks ) {
112
+ foreach ( $hooks as $hook => $keys ) {
113
+ foreach ( $keys as $key => $data ) {
114
+ if ( $hook == 'w3_pgcache_prime' && count( $data['args'] ) ) {
115
+ return;
116
+ }
117
  }
118
  }
119
  }
146
 
147
 
148
 
149
+ // use 'WordPress' since by default we use W3TC-powered by
150
  // which blocks caching
151
  foreach ( $queue as $url )
152
+ Util_Http::get( $url, array( 'user-agent' => 'WordPress' ) );
153
  }
154
 
155
  /**
223
 
224
  // Make HTTP requests and prime cache
225
  foreach ( $post_urls as $url ) {
226
+ $result = Util_Http::get( $url, array( 'user-agent' => 'WordPress' ) );
227
  if ( is_wp_error( $result ) )
228
  return false;
229
  }
273
  if ( $this->_config->get_string( 'pgcache.engine' ) == 'memcached' ) {
274
  $summary['memcached_servers']['pgcache'] = array(
275
  'servers' => $this->_config->get_array( 'pgcache.memcached.servers' ),
276
+ 'username' => $this->_config->get_string( 'pgcache.memcached.username' ),
277
+ 'password' => $this->_config->get_string( 'pgcache.memcached.password' ),
278
  'name' => __( 'Page Cache', 'w3-total-cache' )
279
  );
280
  } elseif ( $this->_config->get_string( 'pgcache.engine' ) == 'redis' ) {
281
  $summary['redis_servers']['pgcache'] = array(
282
  'servers' => $this->_config->get_array( 'pgcache.redis.servers' ),
283
+ 'dbid' => $this->_config->get_integer( 'pgcache.redis.dbid' ),
284
+ 'password' => $this->_config->get_string( 'pgcache.redis.password' ),
 
285
  'name' => __( 'Page Cache', 'w3-total-cache' )
286
  );
287
  }
UsageStatistics_Widget.php CHANGED
@@ -5,11 +5,19 @@ namespace W3TC;
5
  * widget with stats
6
  */
7
  class UsageStatistics_Widget {
8
- function init() {
 
 
 
 
 
 
9
  add_action( 'admin_print_styles-toplevel_page_w3tc_dashboard',
10
  array( $this, 'admin_print_styles_w3tc_dashboard' ) );
11
- add_action( 'admin_print_scripts-toplevel_page_w3tc_dashboard',
12
- array( $this, 'admin_print_scripts_w3tc_dashboard' ) );
 
 
13
 
14
  add_action( 'w3tc_widget_setup', array(
15
  $this,
@@ -20,7 +28,7 @@ class UsageStatistics_Widget {
20
 
21
 
22
 
23
- function w3tc_widget_setup() {
24
  Util_Widget::add( 'w3tc_usage_statistics',
25
  '<div class="w3tc-widget-w3tc-logo"></div>' .
26
  '<div class="w3tc-widget-text">' .
@@ -33,11 +41,11 @@ class UsageStatistics_Widget {
33
 
34
 
35
 
36
- function widget_form() {
37
  $storage = new UsageStatistics_StorageReader();
38
  $summary_promise = $storage->get_history_summary_promise();
39
- $c = Dispatcher::config();
40
- if ( $c->get_boolean( 'stats.enabled' ) && Util_Environment::is_w3tc_pro( $c ) )
41
  include W3TC_DIR . '/UsageStatistics_Widget_View.php';
42
  else
43
  include W3TC_DIR . '/UsageStatistics_Widget_View_Disabled.php';
5
  * widget with stats
6
  */
7
  class UsageStatistics_Widget {
8
+ private $enabled = false;
9
+
10
+ public function init() {
11
+ $c = Dispatcher::config();
12
+ $this->enabled = ( $c->get_boolean( 'stats.enabled' ) &&
13
+ Util_Environment::is_w3tc_pro( $c ) );
14
+
15
  add_action( 'admin_print_styles-toplevel_page_w3tc_dashboard',
16
  array( $this, 'admin_print_styles_w3tc_dashboard' ) );
17
+
18
+ if ( $this->enabled )
19
+ add_action( 'admin_print_scripts-toplevel_page_w3tc_dashboard',
20
+ array( $this, 'admin_print_scripts_w3tc_dashboard' ) );
21
 
22
  add_action( 'w3tc_widget_setup', array(
23
  $this,
28
 
29
 
30
 
31
+ public function w3tc_widget_setup() {
32
  Util_Widget::add( 'w3tc_usage_statistics',
33
  '<div class="w3tc-widget-w3tc-logo"></div>' .
34
  '<div class="w3tc-widget-text">' .
41
 
42
 
43
 
44
+ public function widget_form() {
45
  $storage = new UsageStatistics_StorageReader();
46
  $summary_promise = $storage->get_history_summary_promise();
47
+
48
+ if ( $this->enabled )
49
  include W3TC_DIR . '/UsageStatistics_Widget_View.php';
50
  else
51
  include W3TC_DIR . '/UsageStatistics_Widget_View_Disabled.php';
UsageStatistics_Widget_View.php CHANGED
@@ -8,108 +8,112 @@ if ( !defined( 'W3TC' ) )
8
  <div class="ustats_error w3tc_none">An error occurred</div>
9
  <div class="ustats_nodata w3tc_none">No data collected</div>
10
  <div class="ustats_content w3tc_hidden">
11
- <p class="ustats_p ustats_top">
12
- Period <span class="ustats_period_timestamp_start_mins"></span>
13
- -
14
- <span class="ustats_period_timestamp_end_mins"></span>
15
- </p>
16
-
17
-
18
-
19
- <?php if ( isset( $summary_promise['pagecache'] ) ): ?>
20
- <div class="ustats_header">Page Cache:</div>
21
- <?php if ( $summary_promise['pagecache']['size_visible'] ): ?>
22
- Cache size: <span class="ustats_pagecache_size_used"></span><br />
23
- Entries: <span class="ustats_pagecache_items"></span><br />
24
- <?php endif; ?>
25
- <?php if ( $summary_promise['pagecache']['requests_visible'] ): ?>
26
- Requests/period: <span class="ustats_pagecache_requests_total"></span><br />
27
- Requests/sec: <span class="ustats_pagecache_requests_per_second"></span><br />
28
- Avg processing time (ms): <span class="ustats_pagecache_request_time_ms"></span><br />
29
- Hit rate: <span class="ustats_pagecache_hit_rate"></span><br />
30
- <?php endif; ?>
31
- <br />
32
- <?php endif; ?>
33
-
34
-
35
-
36
- <?php if ( isset( $summary_promise['minify'] ) ): ?>
37
- <div class="ustats_header">Minify:</div>
38
- <?php if ( $summary_promise['minify']['size_visible'] ): ?>
39
- Used: <span class="ustats_minify_size_used"></span><br />
40
- Files: <span class="ustats_minify_size_items"></span><br />
41
- CSS compression in cache: <span class="ustats_minify_size_compression_css"></span><br />
42
- JS compression in cache: <span class="ustats_minify_size_compression_js"></span><br />
43
- <?php endif ?>
44
- <?php if ( $summary_promise['minify']['requests_visible'] ): ?>
45
- Requests/period: <span class="ustats_minify_requests_total"></span><br />
46
- Requests/sec: <span class="ustats_minify_requests_per_second"></span><br />
47
- Responded CSS compression: <span class="ustats_minify_compression_css"></span><br />
48
- Responded JS compression: <span class="ustats_minify_compression_js"></span><br />
49
- <?php endif; ?>
50
- <br />
51
- <?php endif; ?>
52
-
53
-
54
-
55
- <?php if ( isset( $summary_promise['objectcache'] ) ): ?>
56
- <div class="ustats_header">Object Cache:</div>
57
- Calls/period: <span class="ustats_objectcache_calls_total"></span><br />
58
- Calls/sec: <span class="ustats_objectcache_calls_per_second"></span><br />
59
- Hit rate: <span class="ustats_objectcache_hit_rate"></span><br />
60
- <br />
61
- <?php endif; ?>
62
-
63
-
64
-
65
- <?php if ( isset( $summary_promise['fragmentcache'] ) ): ?>
66
- <div class="ustats_header">Fragment Cache:</div>
67
- Calls/period: <span class="ustats_fragmentcache_calls_total"></span><br />
68
- Calls/sec: <span class="ustats_fragmentcache_calls_per_second"></span><br />
69
- Hit rate: <span class="ustats_fragmentcache_hit_rate"></span><br />
70
- <br />
71
- <?php endif; ?>
72
-
73
-
74
-
75
- <?php if ( isset( $summary_promise['dbcache'] ) ): ?>
76
- <?php $m = $summary_promise['dbcache']; ?>
77
- <div class="ustats_header">Database Cache:</div>
78
- Calls/period: <span class="ustats_dbcache_calls_total"></span><br />
79
- Calls/sec: <span class="ustats_dbcache_calls_per_second"></span><br />
80
- Hit rate: <span class="ustats_dbcache_hit_rate"></span><br />
81
- <br />
82
- <?php endif; ?>
83
-
84
-
85
-
86
- PHP Memory: <span class="ustats_php_memory"></span><br />
87
- WordPress requests/period: <span class="ustats_php_wp_requests_total"></span><br />
88
- WordPress requests/sec: <span class="ustats_php_wp_requests_per_second"></span><br />
89
- <br />
90
-
91
-
92
- <?php if ( !empty( $summary_promise['memcached'] ) ): ?>
93
- <?php foreach ( $summary_promise['memcached'] as $id => $m ): ?>
94
- <div class="ustats_header">Memcached <?php echo $m['name'] ?></div>
95
- Used by <?php echo implode( ',', $m['module_names'] ) ?><br />
96
- Evictions/sec: <span class="ustats_memcached_<?php echo $id ?>_evictions_per_second"></span><br />
97
- Used: <span class="ustats_memcached_<?php echo $id ?>_size_used"></span><br />
98
- Used (%): <span class="ustats_memcached_<?php echo $id ?>_size_percent"></span><br />
99
- Hit rate: <span class="ustats_memcached_<?php echo $id ?>_get_hit_rate"></span><br />
100
- <?php endforeach ?>
101
- <?php endif; ?>
102
-
103
-
104
- <?php if ( !empty( $summary_promise['redis'] ) ): ?>
105
- <?php foreach ( $summary_promise['redis'] as $id => $m ): ?>
106
- <div class="ustats_header">Redis <?php echo $m['name'] ?></div>
107
- Used by <?php echo implode( ',', $m['module_names'] ) ?><br />
108
- Evictions/sec: <span class="ustats_redis_<?php echo $id ?>_evictions_per_second"></span><br />
109
- Expirations/sec: <span class="ustats_redis_<?php echo $id ?>_expirations_per_second"></span><br />
110
- Used: <span class="ustats_redis_<?php echo $id ?>_size_used"></span><br />
111
- Hit rate: <span class="ustats_redis_<?php echo $id ?>_hit_rate"></span><br />
112
- <?php endforeach ?>
113
- <?php endif; ?>
 
 
 
 
114
  </div>
115
  <a href="#" class="ustats_reload">Refresh</a>
8
  <div class="ustats_error w3tc_none">An error occurred</div>
9
  <div class="ustats_nodata w3tc_none">No data collected</div>
10
  <div class="ustats_content w3tc_hidden">
11
+ <p class="ustats_p ustats_top">
12
+ Period <span class="ustats_period_timestamp_start_mins"></span>
13
+ -
14
+ <span class="ustats_period_timestamp_end_mins"></span>
15
+ </p>
16
+
17
+
18
+
19
+ <?php if ( isset( $summary_promise['pagecache'] ) ): ?>
20
+ <div class="ustats_header">Page Cache:</div>
21
+ <?php if ( $summary_promise['pagecache']['size_visible'] ): ?>
22
+ Cache size: <span class="ustats_pagecache_size_used"></span><br />
23
+ Entries: <span class="ustats_pagecache_items"></span><br />
24
+ <?php endif; ?>
25
+ <?php if ( $summary_promise['pagecache']['requests_visible'] ): ?>
26
+ Requests/period: <span class="ustats_pagecache_requests_total"></span><br />
27
+ Requests/sec: <span class="ustats_pagecache_requests_per_second"></span><br />
28
+ Avg processing time (ms): <span class="ustats_pagecache_request_time_ms"></span><br />
29
+ Hit rate: <span class="ustats_pagecache_hit_rate"></span><br />
30
+ <?php endif; ?>
31
+ <br />
32
+ <?php endif; ?>
33
+
34
+
35
+
36
+ <?php if ( isset( $summary_promise['minify'] ) ): ?>
37
+ <div class="ustats_header">Minify:</div>
38
+ <?php if ( $summary_promise['minify']['size_visible'] ): ?>
39
+ Used: <span class="ustats_minify_size_used"></span><br />
40
+ Files: <span class="ustats_minify_size_items"></span><br />
41
+ CSS compression in cache: <span class="ustats_minify_size_compression_css"></span><br />
42
+ JS compression in cache: <span class="ustats_minify_size_compression_js"></span><br />
43
+ <?php endif ?>
44
+ <?php if ( $summary_promise['minify']['requests_visible'] ): ?>
45
+ Requests/period: <span class="ustats_minify_requests_total"></span><br />
46
+ Requests/sec: <span class="ustats_minify_requests_per_second"></span><br />
47
+ Responded CSS compression: <span class="ustats_minify_compression_css"></span><br />
48
+ Responded JS compression: <span class="ustats_minify_compression_js"></span><br />
49
+ <?php endif; ?>
50
+ <br />
51
+ <?php endif; ?>
52
+
53
+
54
+
55
+ <?php if ( isset( $summary_promise['objectcache'] ) ): ?>
56
+ <div class="ustats_header">Object Cache:</div>
57
+ Calls/period: <span class="ustats_objectcache_calls_total"></span><br />
58
+ Calls/sec: <span class="ustats_objectcache_calls_per_second"></span><br />
59
+ Hit rate: <span class="ustats_objectcache_hit_rate"></span><br />
60
+ <br />
61
+ <?php endif; ?>
62
+
63
+
64
+
65
+ <?php if ( isset( $summary_promise['fragmentcache'] ) ): ?>
66
+ <div class="ustats_header">Fragment Cache:</div>
67
+ Calls/period: <span class="ustats_fragmentcache_calls_total"></span><br />
68
+ Calls/sec: <span class="ustats_fragmentcache_calls_per_second"></span><br />
69
+ Hit rate: <span class="ustats_fragmentcache_hit_rate"></span><br />
70
+ <br />
71
+ <?php endif; ?>
72
+
73
+
74
+
75
+ <?php if ( isset( $summary_promise['dbcache'] ) ): ?>
76
+ <?php $m = $summary_promise['dbcache']; ?>
77
+ <div class="ustats_header">Database Cache:</div>
78
+ Calls/period: <span class="ustats_dbcache_calls_total"></span><br />
79
+ Calls/sec: <span class="ustats_dbcache_calls_per_second"></span><br />
80
+ Hit rate: <span class="ustats_dbcache_hit_rate"></span><br />
81
+ <br />
82
+ <?php endif; ?>
83
+
84
+
85
+
86
+ <div class="ustats_header">PHP Memory:</div>
87
+ <span class="ustats_php_memory"></span><br />
88
+
89
+
90
+
91
+ WordPress requests/period: <span class="ustats_php_wp_requests_total"></span><br />
92
+ WordPress requests/sec: <span class="ustats_php_wp_requests_per_second"></span><br />
93
+ <br />
94
+
95
+
96
+ <?php if ( !empty( $summary_promise['memcached'] ) ): ?>
97
+ <?php foreach ( $summary_promise['memcached'] as $id => $m ): ?>
98
+ <div class="ustats_header">Memcached <?php echo $m['name'] ?></div>
99
+ Used by <?php echo implode( ',', $m['module_names'] ) ?><br />
100
+ Evictions/sec: <span class="ustats_memcached_<?php echo $id ?>_evictions_per_second"></span><br />
101
+ Used: <span class="ustats_memcached_<?php echo $id ?>_size_used"></span><br />
102
+ Used (%): <span class="ustats_memcached_<?php echo $id ?>_size_percent"></span><br />
103
+ Hit rate: <span class="ustats_memcached_<?php echo $id ?>_get_hit_rate"></span><br />
104
+ <?php endforeach ?>
105
+ <?php endif; ?>
106
+
107
+
108
+ <?php if ( !empty( $summary_promise['redis'] ) ): ?>
109
+ <?php foreach ( $summary_promise['redis'] as $id => $m ): ?>
110
+ <div class="ustats_header">Redis <?php echo $m['name'] ?></div>
111
+ Used by <?php echo implode( ',', $m['module_names'] ) ?><br />
112
+ Evictions/sec: <span class="ustats_redis_<?php echo $id ?>_evictions_per_second"></span><br />
113
+ Expirations/sec: <span class="ustats_redis_<?php echo $id ?>_expirations_per_second"></span><br />
114
+ Used: <span class="ustats_redis_<?php echo $id ?>_size_used"></span><br />
115
+ Hit rate: <span class="ustats_redis_<?php echo $id ?>_hit_rate"></span><br />
116
+ <?php endforeach ?>
117
+ <?php endif; ?>
118
  </div>
119
  <a href="#" class="ustats_reload">Refresh</a>
Util_Content.php CHANGED
@@ -3,12 +3,31 @@ namespace W3TC;
3
 
4
  class Util_Content {
5
  /**
6
- * Check if content is HTML or XML
7
  *
8
  * @param string $content
9
  * @return boolean
10
  */
11
  static public function is_html( $content ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  if ( strlen( $content ) > 1000 ) {
13
  $content = substr( $content, 0, 1000 );
14
  }
@@ -18,8 +37,7 @@ class Util_Content {
18
  }
19
 
20
  $content = ltrim( $content, "\x00\x09\x0A\x0D\x20\xBB\xBF\xEF" );
21
-
22
- return stripos( $content, '<?xml' ) === 0 || stripos( $content, '<html' ) === 0 || stripos( $content, '<!DOCTYPE' ) === 0;
23
  }
24
 
25
  /**
@@ -30,8 +48,8 @@ class Util_Content {
30
  */
31
  static public function can_print_comment( $buffer ) {
32
  if ( function_exists( 'apply_filters' ) )
33
- return apply_filters( 'w3tc_can_print_comment', Util_Content::is_html( $buffer ) && !defined( 'DOING_AJAX' ) );
34
- return Util_Content::is_html( $buffer ) && !defined( 'DOING_AJAX' );
35
  }
36
 
37
 
3
 
4
  class Util_Content {
5
  /**
6
+ * Check if content is HTML
7
  *
8
  * @param string $content
9
  * @return boolean
10
  */
11
  static public function is_html( $content ) {
12
+ $content = Util_Content::_is_html_prepare( $content );
13
+ return stripos( $content, '<html' ) === 0 ||
14
+ stripos( $content, '<!DOCTYPE' ) === 0;
15
+ }
16
+
17
+ /**
18
+ * Check if content is HTML or XML
19
+ *
20
+ * @param string $content
21
+ * @return boolean
22
+ */
23
+ static public function is_html_xml( $content ) {
24
+ $content = Util_Content::_is_html_prepare( $content );
25
+ return stripos( $content, '<?xml' ) === 0 ||
26
+ stripos( $content, '<html' ) === 0 ||
27
+ stripos( $content, '<!DOCTYPE' ) === 0;
28
+ }
29
+
30
+ static private function _is_html_prepare( $content ) {
31
  if ( strlen( $content ) > 1000 ) {
32
  $content = substr( $content, 0, 1000 );
33
  }
37
  }
38
 
39
  $content = ltrim( $content, "\x00\x09\x0A\x0D\x20\xBB\xBF\xEF" );
40
+ return $content;
 
41
  }
42
 
43
  /**
48
  */
49
  static public function can_print_comment( $buffer ) {
50
  if ( function_exists( 'apply_filters' ) )
51
+ return apply_filters( 'w3tc_can_print_comment', Util_Content::is_html_xml( $buffer ) && !defined( 'DOING_AJAX' ) );
52
+ return Util_Content::is_html_xml( $buffer ) && !defined( 'DOING_AJAX' );
53
  }
54
 
55
 
Util_Debug.php CHANGED
@@ -45,7 +45,7 @@ class Util_Debug {
45
  $filename = $dir_path . '/' . $postfix . '/' . $module . '.log';
46
  if ( !is_dir( dirname( $filename ) ) ) {
47
 
48
- Util_File::mkdir_from( dirname( $filename ), $from_dir );
49
  }
50
 
51
  return $filename;
45
  $filename = $dir_path . '/' . $postfix . '/' . $module . '.log';
46
  if ( !is_dir( dirname( $filename ) ) ) {
47
 
48
+ Util_File::mkdir_from_safe( dirname( $filename ), $from_dir );
49
  }
50
 
51
  return $filename;
Util_Environment.php CHANGED
@@ -108,7 +108,7 @@ class Util_Environment {
108
  }
109
 
110
  /*
111
- * Returns URI from filename/dirname
112
  *
113
  * @return string
114
  */
@@ -118,6 +118,11 @@ class Util_Environment {
118
  if ( substr( $filename, 0, strlen( WP_CONTENT_DIR ) ) != WP_CONTENT_DIR )
119
  return '';
120
  $uri_from_wp_content = substr( $filename, strlen( WP_CONTENT_DIR ) );
 
 
 
 
 
121
  $url = content_url( $uri_from_wp_content );
122
  $url = apply_filters( 'w3tc_filename_to_url', $url );
123
 
@@ -282,6 +287,19 @@ class Util_Environment {
282
  return '';
283
  }
284
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
  /**
286
  * Returns current blog ID
287
  *
@@ -565,20 +583,7 @@ class Util_Environment {
565
  * @return string
566
  */
567
  static public function site_url_uri() {
568
- $site_url = site_url();
569
- $parse_url = @parse_url( $site_url );
570
-
571
- if ( $parse_url && isset( $parse_url['path'] ) ) {
572
- $site_path = '/' . ltrim( $parse_url['path'], '/' );
573
- } else {
574
- $site_path = '/';
575
- }
576
-
577
- if ( substr( $site_path, -1 ) != '/' ) {
578
- $site_path .= '/';
579
- }
580
-
581
- return $site_path;
582
  }
583
 
584
  /**
@@ -611,24 +616,18 @@ class Util_Environment {
611
  * @return string
612
  */
613
  static public function home_url_uri() {
614
- $home_url = get_home_url();
615
- $parse_url = @parse_url( $home_url );
616
-
617
- if ( $parse_url && isset( $parse_url['path'] ) ) {
618
- $home_path = '/' . ltrim( $parse_url['path'], '/' );
619
- } else {
620
- $home_path = '/';
621
- }
622
-
623
- if ( substr( $home_path, -1 ) != '/' ) {
624
- $home_path .= '/';
625
- }
626
-
627
- return $home_path;
628
  }
629
 
630
  static public function network_home_url_uri() {
631
  $uri = network_home_url( '', 'relative' );
 
 
 
 
 
 
 
632
  if ( empty( $uri ) )
633
  return '/';
634
 
@@ -804,7 +803,7 @@ class Util_Environment {
804
  // common encoded characters
805
  $path_relative_to_home = str_replace( '%20', ' ', $path_relative_to_home );
806
 
807
- $full_filename = $home_path . DIRECTORY_SEPARATOR .
808
  trim( $path_relative_to_home, DIRECTORY_SEPARATOR );
809
 
810
  $docroot = Util_Environment::document_root();
@@ -1039,12 +1038,20 @@ class Util_Environment {
1039
  * @return bool
1040
  */
1041
  static public function is_w3tc_pro( $config = null ) {
1042
- $result = $config->get_string( 'plugin.type' ) == 'pro' ||
1043
- $config->get_string( 'plugin.type' ) == 'pro_dev' ||
1044
- Util_Environment::is_w3tc_enterprise( $config ) ||
1045
- ( defined( 'W3TC_PRO' ) && W3TC_PRO );
1046
 
1047
- return $result;
 
 
 
 
 
 
 
 
 
 
1048
  }
1049
 
1050
  /**
@@ -1063,12 +1070,14 @@ class Util_Environment {
1063
  * @return bool
1064
  */
1065
  static public function is_w3tc_enterprise( $config = null ) {
1066
- $result = false;
1067
- if ( $config )
1068
- $result = $config->get_string( 'plugin.type' ) == 'enterprise' ||
1069
- ( defined( 'W3TC_ENTERPRISE' ) && W3TC_ENTERPRISE );
1070
 
1071
- return $result;
 
 
 
 
1072
  }
1073
 
1074
  /**
108
  }
109
 
110
  /*
111
+ * Returns URL from filename/dirname
112
  *
113
  * @return string
114
  */
118
  if ( substr( $filename, 0, strlen( WP_CONTENT_DIR ) ) != WP_CONTENT_DIR )
119
  return '';
120
  $uri_from_wp_content = substr( $filename, strlen( WP_CONTENT_DIR ) );
121
+
122
+ if ( DIRECTORY_SEPARATOR != '/' )
123
+ $uri_from_wp_content = str_replace( DIRECTORY_SEPARATOR, '/',
124
+ $uri_from_wp_content );
125
+
126
  $url = content_url( $uri_from_wp_content );
127
  $url = apply_filters( 'w3tc_filename_to_url', $url );
128
 
287
  return '';
288
  }
289
 
290
+ /**
291
+ * Returns path from URL. Without trailing slash
292
+ */
293
+ static public function url_to_uri( $url ) {
294
+ $uri = @parse_url( $url, PHP_URL_PATH );
295
+
296
+ // convert FALSE and other return values to string
297
+ if ( empty( $uri ) )
298
+ return '';
299
+
300
+ return rtrim( $uri, '/' );
301
+ }
302
+
303
  /**
304
  * Returns current blog ID
305
  *
583
  * @return string
584
  */
585
  static public function site_url_uri() {
586
+ return Util_Environment::url_to_uri( site_url() ) . '/';
 
 
 
 
 
 
 
 
 
 
 
 
 
587
  }
588
 
589
  /**
616
  * @return string
617
  */
618
  static public function home_url_uri() {
619
+ return Util_Environment::url_to_uri( get_home_url() ) . '/';
 
 
 
 
 
 
 
 
 
 
 
 
 
620
  }
621
 
622
  static public function network_home_url_uri() {
623
  $uri = network_home_url( '', 'relative' );
624
+
625
+ /* There is a bug in WP where network_home_url can return
626
+ * a non-relative URI even though scheme is set to relative.
627
+ */
628
+ if ( Util_Environment::is_url( $uri ) )
629
+ $uri = parse_url( $uri, PHP_URL_PATH );
630
+
631
  if ( empty( $uri ) )
632
  return '/';
633
 
803
  // common encoded characters
804
  $path_relative_to_home = str_replace( '%20', ' ', $path_relative_to_home );
805
 
806
+ $full_filename = $home_path . DIRECTORY_SEPARATOR .
807
  trim( $path_relative_to_home, DIRECTORY_SEPARATOR );
808
 
809
  $docroot = Util_Environment::document_root();
1038
  * @return bool
1039
  */
1040
  static public function is_w3tc_pro( $config = null ) {
1041
+ if ( defined( 'W3TC_PRO' ) && W3TC_PRO )
1042
+ return true;
 
 
1043
 
1044
+ if ( is_object( $config ) ) {
1045
+ $plugin_type = $config->get_string( 'plugin.type' );
1046
+
1047
+ if ( $plugin_type == 'pro' || $plugin_type == 'pro_dev' )
1048
+ return true;
1049
+ }
1050
+
1051
+ if ( Util_Environment::is_w3tc_enterprise( $config ) )
1052
+ return true;
1053
+
1054
+ return false;
1055
  }
1056
 
1057
  /**
1070
  * @return bool
1071
  */
1072
  static public function is_w3tc_enterprise( $config = null ) {
1073
+ if ( defined( 'W3TC_ENTERPRISE' ) && W3TC_ENTERPRISE )
1074
+ return true;
 
 
1075
 
1076
+ if ( is_object( $config ) &&
1077
+ $config->get_string( 'plugin.type' ) == 'enterprise' )
1078
+ return true;
1079
+
1080
+ return false;
1081
  }
1082
 
1083
  /**
Util_File.php CHANGED
@@ -56,16 +56,56 @@ class Util_File {
56
  $curr_path = $from_path;
57
 
58
  foreach ( $dirs as $dir ) {
59
- if ( $dir == '' ) {
60
  return false;
 
 
 
 
 
 
61
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
  $curr_path .= ( $curr_path == '' ? '' : '/' ) . $dir;
64
 
65
  if ( !@is_dir( $curr_path ) ) {
66
- if ( !@mkdir( $curr_path, $mask ) ) {
67
  return false;
68
- }
69
  }
70
  }
71
 
@@ -293,8 +333,11 @@ class Util_File {
293
  Util_File::mkdir_from( W3TC_CACHE_TMP_DIR, W3TC_CACHE_DIR );
294
 
295
  if ( !is_dir( W3TC_CACHE_TMP_DIR ) || !is_writable( W3TC_CACHE_TMP_DIR ) ) {
 
 
 
296
  throw new \Exception( 'Can\'t create folder <strong>' .
297
- W3TC_CACHE_TMP_DIR . '</strong>' );
298
  }
299
  }
300
 
56
  $curr_path = $from_path;
57
 
58
  foreach ( $dirs as $dir ) {
59
+ if ( $dir == '' )
60
  return false;
61
+
62
+ $curr_path .= ( $curr_path == '' ? '' : '/' ) . $dir;
63
+
64
+ if ( !@is_dir( $curr_path ) ) {
65
+ if ( !@mkdir( $curr_path, $mask ) )
66
+ return false;
67
  }
68
+ }
69
+
70
+ return true;
71
+ }
72
+
73
+ /**
74
+ * Recursive creates directory from some directory
75
+ * Safely for web-accessible folders
76
+ * (no .htaccess folders which cause 403 error later)
77
+ * Does not try to create directory before from
78
+ *
79
+ * @param string $path
80
+ * @param string $from_path
81
+ * @param integer $mask
82
+ * @return boolean
83
+ */
84
+ static public function mkdir_from_safe( $path, $from_path = '', $mask = 0777 ) {
85
+ $path = Util_Environment::realpath( $path );
86
+
87
+ $from_path = Util_Environment::realpath( $from_path );
88
+ if ( substr( $path, 0, strlen( $from_path ) ) != $from_path )
89
+ return false;
90
+
91
+ $path = substr( $path, strlen( $from_path ) );
92
+
93
+ $path = trim( $path, '/' );
94
+ $dirs = explode( '/', $path );
95
+
96
+ $curr_path = $from_path;
97
+
98
+ foreach ( $dirs as $dir ) {
99
+ if ( $dir == '' )
100
+ return false;
101
+ if ( substr( $dir, 0, 1 ) == '.' ) // (no .htaccess folders)
102
+ return false;
103
 
104
  $curr_path .= ( $curr_path == '' ? '' : '/' ) . $dir;
105
 
106
  if ( !@is_dir( $curr_path ) ) {
107
+ if ( !@mkdir( $curr_path, $mask ) )
108
  return false;
 
109
  }
110
  }
111
 
333
  Util_File::mkdir_from( W3TC_CACHE_TMP_DIR, W3TC_CACHE_DIR );
334
 
335
  if ( !is_dir( W3TC_CACHE_TMP_DIR ) || !is_writable( W3TC_CACHE_TMP_DIR ) ) {
336
+ $e = error_get_last();
337
+ $description = ( isset( $e['message'] ) ? $e['message'] : '' );
338
+
339
  throw new \Exception( 'Can\'t create folder <strong>' .
340
+ W3TC_CACHE_TMP_DIR . '</strong>: ' . $description );
341
  }
342
  }
343
 
Util_PageUrls.php CHANGED
@@ -524,7 +524,7 @@ class Util_PageUrls {
524
  if ( isset( $GLOBALS['post'] ) && is_object( $GLOBALS['post'] ) ) {
525
  $old_post = &$GLOBALS['post'];
526
  } else {
527
- $GLOBALS['post'] = new stdClass();
528
  $old_post = null;
529
  }
530
 
524
  if ( isset( $GLOBALS['post'] ) && is_object( $GLOBALS['post'] ) ) {
525
  $old_post = &$GLOBALS['post'];
526
  } else {
527
+ $GLOBALS['post'] = new \stdClass();
528
  $old_post = null;
529
  }
530
 
Util_Rule.php CHANGED
@@ -2,23 +2,6 @@
2
  namespace W3TC;
3
 
4
  class Util_Rule {
5
- /*
6
- * Returns URI from filename/dirname
7
- * Used for rules mainly since is not usable for regular URI,
8
- * because wordpress adds blogname to uri making it uncompatible with
9
- * directory structure
10
- *
11
- * @return string
12
- */
13
- static public function filename_to_uri( $filename ) {
14
- $url = Util_Environment::filename_to_url( $filename );
15
- $parsed = parse_url( $url );
16
- $uri = isset( $parsed['path'] ) ? ltrim( $parsed['path'], DIRECTORY_SEPARATOR ) : '';
17
- $uri = '/' . $uri;
18
-
19
- return $uri;
20
- }
21
-
22
  /**
23
  * Check if WP permalink directives exists
24
  *
2
  namespace W3TC;
3
 
4
  class Util_Rule {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  /**
6
  * Check if WP permalink directives exists
7
  *
Util_RuleSnippet.php CHANGED
@@ -36,7 +36,7 @@ class Util_RuleSnippet {
36
 
37
  $rules .=
38
  $link_header .
39
- ' if ($request_uri ~ \\.(ttf|ttc|otf|eot|woff|woff2|font.css)$) {' .
40
  "\n " . $link_header .
41
  " " .
42
  str_replace( "\n", "\n ", $add_header_rules ) .
36
 
37
  $rules .=
38
  $link_header .
39
+ ' if ($request_uri ~ ^[^?]*\\.(ttf|ttc|otf|eot|woff|woff2|font.css)(\\?|$)) {' .
40
  "\n " . $link_header .
41
  " " .
42
  str_replace( "\n", "\n ", $add_header_rules ) .
Util_Ui.php CHANGED
@@ -602,7 +602,7 @@ class Util_Ui {
602
  if ( !isset( $a['value'] ) || is_null( $a['value'] ) ) {
603
  $a['value'] = $c->get( $a['key'] );
604
  if ( is_array( $a['value'] ) )
605
- $a['value'] = implode( '\n', $a['value'] );
606
  }
607
 
608
  if ( isset( $a['disabled'] ) && !is_null( $a['disabled'] ) )
602
  if ( !isset( $a['value'] ) || is_null( $a['value'] ) ) {
603
  $a['value'] = $c->get( $a['key'] );
604
  if ( is_array( $a['value'] ) )
605
+ $a['value'] = implode( "\n", $a['value'] );
606
  }
607
 
608
  if ( isset( $a['disabled'] ) && !is_null( $a['disabled'] ) )
Util_WpFile.php CHANGED
@@ -85,7 +85,7 @@ class Util_WpFile {
85
  if ( @is_dir( $folder ) )
86
  return;
87
 
88
- if ( Util_File::mkdir_from( $folder, $from_folder ) )
89
  return;
90
 
91
  try {
85
  if ( @is_dir( $folder ) )
86
  return;
87
 
88
+ if ( Util_File::mkdir_from_safe( $folder, $from_folder ) )
89
  return;
90
 
91
  try {
inc/lightbox/self_test.php CHANGED
@@ -166,15 +166,6 @@ if ( !defined( 'W3TC' ) )
166
  <span class="w3tc-self-test-hint"><?php _e( '(required for NetDNA / MaxCDN <acronym title="Content Delivery Network">CDN</acronym> purge support)', 'w3-total-cache' ); ?></span>
167
  </li>
168
 
169
- <li>
170
- <?php _e( 'Safe mode:', 'w3-total-cache' ); ?>
171
- <?php if ( Util_Environment::to_boolean( ini_get( 'safe_mode' ) ) ): ?>
172
- <code><?php _e( 'On', 'w3-total-cache' ); ?></code>
173
- <?php else: ?>
174
- <code><?php _e( 'Off', 'w3-total-cache' ); ?></code>
175
- <?php endif; ?>
176
- </li>
177
-
178
  <li>
179
  <?php _e( 'Open basedir:', 'w3-total-cache' ); ?>
180
  <?php $open_basedir = ini_get( 'open_basedir' ); if ( $open_basedir ): ?>
166
  <span class="w3tc-self-test-hint"><?php _e( '(required for NetDNA / MaxCDN <acronym title="Content Delivery Network">CDN</acronym> purge support)', 'w3-total-cache' ); ?></span>
167
  </li>
168
 
 
 
 
 
 
 
 
 
 
169
  <li>
170
  <?php _e( 'Open basedir:', 'w3-total-cache' ); ?>
171
  <?php $open_basedir = ini_get( 'open_basedir' ); if ( $open_basedir ): ?>
inc/mime/html.php CHANGED
@@ -6,7 +6,7 @@
6
  return array(
7
  'html|htm' => 'text/html',
8
  'rtf|rtx' => 'text/richtext',
9
- 'svg|svgz' => 'image/svg+xml',
10
  'txt' => 'text/plain',
11
  'xsd' => 'text/xsd',
12
  'xsl' => 'text/xsl',
6
  return array(
7
  'html|htm' => 'text/html',
8
  'rtf|rtx' => 'text/richtext',
9
+ 'svg' => 'image/svg+xml',
10
  'txt' => 'text/plain',
11
  'xsd' => 'text/xsd',
12
  'xsl' => 'text/xsl',
inc/mime/other.php CHANGED
@@ -16,6 +16,7 @@ return array(
16
  'gz|gzip' => 'application/x-gzip',
17
  'ico' => 'image/x-icon',
18
  'jpg|jpeg|jpe' => 'image/jpeg',
 
19
  'json' => 'application/json',
20
  'mdb' => 'application/vnd.ms-access',
21
  'mid|midi' => 'audio/midi',
16
  'gz|gzip' => 'application/x-gzip',
17
  'ico' => 'image/x-icon',
18
  'jpg|jpeg|jpe' => 'image/jpeg',
19
+ 'webp' => 'image/webp',
20
  'json' => 'application/json',
21
  'mdb' => 'application/vnd.ms-access',
22
  'mid|midi' => 'audio/midi',
inc/options/cdn.php CHANGED
@@ -124,7 +124,7 @@ if ( !$upload_blogfiles_enabled )
124
  <th<?php if ( $cdn_mirror ): ?> colspan="2"<?php endif; ?>>
125
  <?php $this->checkbox( 'cdn.custom.enable' ) ?> <?php Util_Ui::e_config_label( 'cdn.custom.enable' ) ?></label><br />
126
  <span class="description">
127
- <?php echo sprintf( __( 'If checked, any file names or paths specified in the "custom file list" field below will be hosted with the <acronym title="Content Delivery Network">CDN</acronym>. Supports regular expressions (See <a href="%s">FAQ</a>)', 'w3-total-cache' ), network_admin_url( 'admin.php?page=w3tc_faq#q82' ) ); ?>
128
  </span>
129
  </th>
130
  <?php if ( ! $cdn_mirror ): ?>
124
  <th<?php if ( $cdn_mirror ): ?> colspan="2"<?php endif; ?>>
125
  <?php $this->checkbox( 'cdn.custom.enable' ) ?> <?php Util_Ui::e_config_label( 'cdn.custom.enable' ) ?></label><br />
126
  <span class="description">
127
+ <?php echo sprintf( __( 'If checked, any file names or paths specified in the "custom file list" field below will be hosted with the <acronym title="Content Delivery Network">CDN</acronym>. Supports masks (See <a href="%s">FAQ</a>)', 'w3-total-cache' ), network_admin_url( 'admin.php?page=w3tc_faq#q82' ) ); ?>
128
  </span>
129
  </th>
130
  <?php if ( ! $cdn_mirror ): ?>
inc/options/minify.php CHANGED
@@ -311,6 +311,17 @@ if ( file_exists( $js_engine_file2 ) ) {
311
  </td>
312
  </tr>
313
  <?php endif; ?>
 
 
 
 
 
 
 
 
 
 
 
314
  </table>
315
 
316
  <?php Util_Ui::button_config_save( 'minify_js' ); ?>
@@ -425,6 +436,17 @@ if ( file_exists( $css_engine_file2 ) ) {
425
  </td>
426
  </tr>
427
  <?php endif; ?>
 
 
 
 
 
 
 
 
 
 
 
428
  </table>
429
 
430
  <?php Util_Ui::button_config_save( 'minify_css' ); ?>
@@ -464,7 +486,7 @@ if ( $this->_config->get_string( 'minify.engine' ) == 'memcached' ) {
464
  <td>
465
  <textarea id="minify_reject_uri" name="minify__reject__uri"
466
  <?php Util_Ui::sealing_disabled( 'minify.' ) ?> cols="40" rows="5"><?php echo esc_textarea( implode( "\r\n", $this->_config->get_array( 'minify.reject.uri' ) ) ); ?></textarea><br />
467
- <span class="description"><?php _e( 'Always ignore the specified pages / directories. Use relative paths. Omit: protocol, hostname, leading forward slash anduery strings.', 'w3-total-cache' ); ?></span>
468
  </td>
469
  </tr>
470
  <tr>
@@ -472,7 +494,7 @@ if ( $this->_config->get_string( 'minify.engine' ) == 'memcached' ) {
472
  <td>
473
  <textarea id="minify_reject_files_js" name="minify__reject__files__js"
474
  <?php Util_Ui::sealing_disabled( 'minify.' ) ?> cols="40" rows="5"><?php echo esc_textarea( implode( "\r\n", $this->_config->get_array( 'minify.reject.files.js' ) ) ); ?></textarea><br />
475
- <span class="description"><?php _e( 'Always ignore the specified <acronym title="JavaScript">JS</acronym> files. Use relative paths. Omit: protocol, hostname, leading forward slash anduery strings.', 'w3-total-cache' ); ?></span>
476
  </td>
477
  </tr>
478
  <tr>
@@ -480,7 +502,7 @@ if ( $this->_config->get_string( 'minify.engine' ) == 'memcached' ) {
480
  <td>
481
  <textarea id="minify_reject_files_css" name="minify__reject__files__css"
482
  <?php Util_Ui::sealing_disabled( 'minify.' ) ?> cols="40" rows="5"><?php echo esc_textarea( implode( "\r\n", $this->_config->get_array( 'minify.reject.files.css' ) ) ); ?></textarea><br />
483
- <span class="description"><?php _e( 'Always ignore the specified <acronym title="Cascading Style Sheet">CSS</acronym> files. Use relative paths. Omit: protocol, hostname, leading forward slash anduery strings.', 'w3-total-cache' ); ?></span>
484
  </td>
485
  </tr>
486
  <tr>
@@ -502,6 +524,13 @@ if ( $this->_config->get_string( 'minify.engine' ) == 'memcached' ) {
502
  <span class="description"><?php _e( 'Specify external files/libraries that should be combined.', 'w3-total-cache' ); ?></span>
503
  </td>
504
  </tr>
 
 
 
 
 
 
 
505
  <?php endif; ?>
506
  </table>
507
 
311
  </td>
312
  </tr>
313
  <?php endif; ?>
314
+ <?php
315
+ Util_Ui::config_item( array(
316
+ 'key' => 'minify.js.http2push',
317
+ 'label' => 'HTTP/2 push',
318
+ 'control' => 'checkbox',
319
+ 'checkbox_label' => __( 'Enable', 'w3-total-cache' ),
320
+ 'description' => __( 'For better performance, send files to browser before they are requested when using the HTTP/2 protocol.',
321
+ 'w3-total-cache' ) .
322
+ ( $this->_config->get_string( 'pgcache.engine' ) != 'file_generic' ? '' :
323
+ __( ' <br /><b>Not supported by "Disk: Enhanced" page cache engine</b>', 'w3-total-cache' ) )
324
+ ) ); ?>
325
  </table>
326
 
327
  <?php Util_Ui::button_config_save( 'minify_js' ); ?>
436
  </td>
437
  </tr>
438
  <?php endif; ?>
439
+ <?php
440
+ Util_Ui::config_item( array(
441
+ 'key' => 'minify.css.http2push',
442
+ 'label' => 'HTTP/2 push',
443
+ 'control' => 'checkbox',
444
+ 'checkbox_label' => __( 'Enable', 'w3-total-cache' ),
445
+ 'description' => __( 'For better performance, send files to browser before they are requested when using the HTTP/2 protocol.',
446
+ 'w3-total-cache' ) .
447
+ ( $this->_config->get_string( 'pgcache.engine' ) != 'file_generic' ? '' :
448
+ __( ' <br /><b>Not supported by "Disk: Enhanced" page cache engine</b>', 'w3-total-cache' ) )
449
+ ) ); ?>
450
  </table>
451
 
452
  <?php Util_Ui::button_config_save( 'minify_css' ); ?>
486
  <td>
487
  <textarea id="minify_reject_uri" name="minify__reject__uri"
488
  <?php Util_Ui::sealing_disabled( 'minify.' ) ?> cols="40" rows="5"><?php echo esc_textarea( implode( "\r\n", $this->_config->get_array( 'minify.reject.uri' ) ) ); ?></textarea><br />
489
+ <span class="description"><?php _e( 'Always ignore the specified pages / directories. Use relative paths. Omit: protocol, hostname, leading forward slash and query strings.', 'w3-total-cache' ); ?></span>
490
  </td>
491
  </tr>
492
  <tr>
494
  <td>
495
  <textarea id="minify_reject_files_js" name="minify__reject__files__js"
496
  <?php Util_Ui::sealing_disabled( 'minify.' ) ?> cols="40" rows="5"><?php echo esc_textarea( implode( "\r\n", $this->_config->get_array( 'minify.reject.files.js' ) ) ); ?></textarea><br />
497
+ <span class="description"><?php _e( 'Always ignore the specified <acronym title="JavaScript">JS</acronym> files. Use relative paths. Omit: protocol, hostname, leading forward slash and query strings.', 'w3-total-cache' ); ?></span>
498
  </td>
499
  </tr>
500
  <tr>
502
  <td>
503
  <textarea id="minify_reject_files_css" name="minify__reject__files__css"
504
  <?php Util_Ui::sealing_disabled( 'minify.' ) ?> cols="40" rows="5"><?php echo esc_textarea( implode( "\r\n", $this->_config->get_array( 'minify.reject.files.css' ) ) ); ?></textarea><br />
505
+ <span class="description"><?php _e( 'Always ignore the specified <acronym title="Cascading Style Sheet">CSS</acronym> files. Use relative paths. Omit: protocol, hostname, leading forward slash and query strings.', 'w3-total-cache' ); ?></span>
506
  </td>
507
  </tr>
508
  <tr>
524
  <span class="description"><?php _e( 'Specify external files/libraries that should be combined.', 'w3-total-cache' ); ?></span>
525
  </td>
526
  </tr>
527
+ <tr>
528
+ <th colspan="2">
529
+ <?php $this->checkbox( 'minify.cache.files_regexp', false, '', true, null ); ?>
530
+ <?php _e( 'Use Regular Expression for matching', 'w3-total-cache' ) ?><br />
531
+ <span class="description"><?php _e( '', 'w3-total-cache' ); ?></span>
532
+ </th>
533
+ </tr>
534
  <?php endif; ?>
535
  </table>
536
 
inc/options/objectcache.php CHANGED
@@ -69,6 +69,19 @@ if ( $this->_config->get_string( 'objectcache.engine' ) == 'memcached' ) {
69
  <br /><span class="description"><?php _e( 'Groups that should not be cached.', 'w3-total-cache' ); ?></span>
70
  </td>
71
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  <?php if ( $this->_config->get_boolean( 'cluster.messagebus.enabled' ) ): ?>
73
  <tr>
74
  <th colspan="2">
69
  <br /><span class="description"><?php _e( 'Groups that should not be cached.', 'w3-total-cache' ); ?></span>
70
  </td>
71
  </tr>
72
+
73
+ <tr>
74
+ <th colspan="2">
75
+ <?php $this->checkbox( 'objectcache.enabled_for_wp_admin' ) ?> Enable caching for wp-admin requests</label>
76
+ <br /><span class="description"><?php _e( 'Enabling this option will increase wp-admin performance, but may cause side-effects', 'w3-total-cache' )?></span>
77
+ </th>
78
+ </tr>
79
+ <tr>
80
+ <th colspan="2">
81
+ <?php $this->checkbox( 'objectcache.fallback_transients' ) ?> Store transients in database</label>
82
+ <br /><span class="description"><?php _e( 'Use that to store transients in database even when external cache is used. That allows transient values to survive object cache cleaning / expiration', 'w3-total-cache' )?></span>
83
+ </th>
84
+ </tr>
85
  <?php if ( $this->_config->get_boolean( 'cluster.messagebus.enabled' ) ): ?>
86
  <tr>
87
  <th colspan="2">
inc/options/parts/memcached.php CHANGED
@@ -40,7 +40,7 @@ if ( !defined( 'W3TC' ) )
40
  if ( !Util_Installed::memcached_aws() )
41
  _e( 'ElastiCache PHP module not found', 'w3-total-cache' );
42
  else
43
- _e( 'When Amazon ElastiCache used, specify configuration endpoint as Memecached host', 'w3-total-cache' );
44
  ?>
45
  </span>
46
  </td>
@@ -56,9 +56,9 @@ $this->value_with_disabled( $module . '.memcached.username',
56
  !Util_Installed::memcached_auth(), '' )
57
  ?> /><br />
58
  <span class="description">
59
- <?php _e( 'Specify memcached username, when SASL authentication used', 'w3-total-cache' );
60
  if ( !Util_Installed::memcached_auth() )
61
- _e( '<br>Available when memcached extension installed, built with SASL, and memcached.use_sasl = 1 option is set in php.ini', 'w3-total-cache' )
62
  ?></span>
63
  </td>
64
  </tr>
@@ -71,6 +71,6 @@ if ( !Util_Installed::memcached_auth() )
71
  $this->value_with_disabled( $module . '.memcached.password',
72
  !Util_Installed::memcached_auth(), '' )
73
  ?> /><br />
74
- <span class="description"><?php _e( 'Specify memcached password, when SASL authentication used', 'w3-total-cache' )?></span>
75
  </td>
76
  </tr>
40
  if ( !Util_Installed::memcached_aws() )
41
  _e( 'ElastiCache PHP module not found', 'w3-total-cache' );
42
  else
43
+ _e( 'When Amazon ElastiCache used, specify configuration endpoint as Memcached host', 'w3-total-cache' );
44
  ?>
45
  </span>
46
  </td>
56
  !Util_Installed::memcached_auth(), '' )
57
  ?> /><br />
58
  <span class="description">
59
+ <?php _e( 'Specify memcached username, when <acronym title="Simple Authentication and Security Layer">SASL</acronym> authentication used', 'w3-total-cache' );
60
  if ( !Util_Installed::memcached_auth() )
61
+ _e( '<br>Available when memcached extension installed, built with <acronym title="Simple Authentication and Security Layer">SASL</acronym>, and memcached.use_sasl = 1 option is set in php.ini', 'w3-total-cache' )
62
  ?></span>
63
  </td>
64
  </tr>
71
  $this->value_with_disabled( $module . '.memcached.password',
72
  !Util_Installed::memcached_auth(), '' )
73
  ?> /><br />
74
+ <span class="description"><?php _e( 'Specify memcached password, when <acronym title="Simple Authentication and Security Layer">SASL</acronym> authentication used', 'w3-total-cache' )?></span>
75
  </td>
76
  </tr>
inc/options/parts/memcached_extension.php CHANGED
@@ -53,9 +53,9 @@ Util_Ui::config_item( array(
53
  'control' => 'textbox',
54
  'disabled' => ( Util_Installed::memcache_auth() ? null : true ),
55
  'description' =>
56
- __( 'Specify memcached username, when SASL authentication used', 'w3-total-cache' ) .
57
  ( Util_Installed::memcache_auth() ? '' :
58
- __( '<br>Available when memcached extension installed, built with SASL, and memcached.use_sasl = 1 option is set in php.ini', 'w3-total-cache' )
59
  )
60
  ) );
61
 
@@ -65,7 +65,7 @@ Util_Ui::config_item( array(
65
  'control' => 'textbox',
66
  'disabled' => ( Util_Installed::memcache_auth() ? null : true ),
67
  'description' =>
68
- __( 'Specify memcached password, when SASL authentication used', 'w3-total-cache' )
69
  ) );
70
 
71
  ?>
53
  'control' => 'textbox',
54
  'disabled' => ( Util_Installed::memcache_auth() ? null : true ),
55
  'description' =>
56
+ __( 'Specify memcached username, when <acronym title="Simple Authentication and Security Layer">SASL</acronym> authentication used', 'w3-total-cache' ) .
57
  ( Util_Installed::memcache_auth() ? '' :
58
+ __( '<br>Available when memcached extension installed, built with <acronym title="Simple Authentication and Security Layer">SASL</acronym>, and memcached.use_sasl = 1 option is set in php.ini', 'w3-total-cache' )
59
  )
60
  ) );
61
 
65
  'control' => 'textbox',
66
  'disabled' => ( Util_Installed::memcache_auth() ? null : true ),
67
  'description' =>
68
+ __( 'Specify memcached password, when <acronym title="Simple Authentication and Security Layer">SASL</acronym> authentication used', 'w3-total-cache' )
69
  ) );
70
 
71
  ?>
inc/options/parts/redis.php CHANGED
@@ -49,6 +49,6 @@ if ( !defined( 'W3TC' ) )
49
  $this->value_with_disabled( $module . '.redis.password',
50
  false, '' )
51
  ?> /><br />
52
- <span class="description"><?php _e( 'Specify redis password, when SASL authentication used', 'w3-total-cache' )?></span>
53
  </td>
54
  </tr>
49
  $this->value_with_disabled( $module . '.redis.password',
50
  false, '' )
51
  ?> /><br />
52
+ <span class="description"><?php _e( 'Specify redis password, when <acronym title="Simple Authentication and Security Layer">SASL</acronym> authentication used', 'w3-total-cache' )?></span>
53
  </td>
54
  </tr>
inc/options/pgcache.php CHANGED
@@ -104,7 +104,7 @@ Util_Ui::config_item( array(
104
  'label' => __( 'Cache alias hostnames:', 'w3-total-cache' ),
105
  'checkbox_label' => __( 'Enable', 'w3-total-cache' ),
106
  'enabled' => !Util_Environment::is_wpmu_subdomain(),
107
- 'description' => __( 'If the same Wordpress content is accessed from different domains',
108
  'w3-total-cache' )
109
  ) );
110
  Util_Ui::config_item( array(
@@ -279,7 +279,7 @@ if ( $this->_config->get_string( 'pgcache.engine' ) == 'memcached' ) {
279
  <th><label><?php _e( 'Compatibility mode:', 'w3-total-cache' ); ?></label></th>
280
  <td>
281
  <?php $this->checkbox( 'pgcache.compatibility' ) ?> <?php Util_Ui::e_config_label( 'pgcache.compatibility' ) ?></label><br />
282
- <span class="description"><?php _e( 'Decreases performance by ~20% at scale in exchange for increasing interoperability with more hosting environments and WordPress idiosyncrasies. This option should be enabled for most sites', 'w3-total-cache' ); ?></span>
283
  </td>
284
  </tr>
285
  <?php if ( !Util_Environment::is_nginx() ): ?>
104
  'label' => __( 'Cache alias hostnames:', 'w3-total-cache' ),
105
  'checkbox_label' => __( 'Enable', 'w3-total-cache' ),
106
  'enabled' => !Util_Environment::is_wpmu_subdomain(),
107
+ 'description' => __( 'If the same WordPress content is accessed from different domains',
108
  'w3-total-cache' )
109
  ) );
110
  Util_Ui::config_item( array(
279
  <th><label><?php _e( 'Compatibility mode:', 'w3-total-cache' ); ?></label></th>
280
  <td>
281
  <?php $this->checkbox( 'pgcache.compatibility' ) ?> <?php Util_Ui::e_config_label( 'pgcache.compatibility' ) ?></label><br />
282
+ <span class="description"><?php _e( 'Decreases performance by ~20% at scale in exchange for increasing interoperability with more hosting environments and WordPress idiosyncrasies. This option should be enabled for most sites.', 'w3-total-cache' ); ?></span>
283
  </td>
284
  </tr>
285
  <?php if ( !Util_Environment::is_nginx() ): ?>
languages/faq-pro-en_US.xml CHANGED
@@ -1,221 +1,221 @@
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <faqs>
3
- <section name="General">
4
- <entry>
5
- <question>
6
- <![CDATA[ Which Pro features are currently available? ]]>
7
- </question>
8
- <answer>
9
- <![CDATA[ <p>Pro features available:</p>
10
- <ul>
11
- <li>Fragment Cache Extension</li>
12
- <li>Genesis Extension</li>
13
- <li>WPML Extension</li>
14
- <li>Full Site Delivery (FSD)</li>
15
- <li>Cache Statistics</li>
16
- </ul>
17
- ]]>
18
- </answer>
19
- </entry>
20
- <entry>
21
- <question><![CDATA[ How do I enable Pro mode on a site that is not registered, i.e a site that was not used for purchase such as local development site?]]></question>
22
- <answer><![CDATA[
23
- <p>Add define('W3TC_PRO_DEV_MODE', true) to wp-config.php and resave the license key.</p>
24
- ]]></answer>
25
- </entry>
26
- </section>
27
- <section name="Usage">
28
- <section name="CDN">
29
- <entry>
30
- <tag>cdn-fsd-maxcdn</tag>
31
- <question><![CDATA[ How do I set up Full Site Delivery (FSD) with MaxCDN? ]]></question>
32
- <answer><![CDATA[
33
- <p>
34
- <ol>
35
- <li>Select CDN provider of your choice in a "Full site mirroring" group of "CDN type" dropdown on "General Settings" page, select MaxCDN there.</li>
36
- <li>Go to "CDN" page.</li>
37
- <li>Click "Authorize" button</li>
38
- <li>Type in API key of your account. You can obtain by following a link in a popup. Opening that link will you will be prompted for your MaxCDN login and password.
39
- Select Zone from the list or choose "Add new" to create new zone (type in some friendly name of zone in that case)</li>
40
- <li>In a zone setup form you will be notified with the settings required for zone. Tou have only 1 editable field is IP address of your Wordpress host. W3 Total Cache tries to guess it, but its not possible to know that in all possible cases.</li>
41
- <li>You get success page with information about DNS changes. Now you need to change record of your wordpress host from IP address and replace it to CNAME to specified hostname.</li>
42
- <li>It works</li>
43
- </ol>
44
- </p>
45
- ]]></answer>
46
- </entry>
47
- <entry>
48
- <tag>cdn-fsd-cloudfront</tag>
49
- <question><![CDATA[ How do I set up Full Site Delivery (FSD) with CloudFront? ]]></question>
50
- <answer><![CDATA[
51
- <p>
52
- <ol>
53
- <li>Select CDN provider of your choice in a "Full site mirroring" group of "CDN type" dropdown on "General Settings" page, select CloudFront there.</li>
54
- <li>Go to "CDN" page.</li>
55
- <li>Click "Authorize" button</li>
56
- <li>Type in Access Key and Secret Key of your account.</li>
57
- <li>Select Distribution from the list or choose "Add new" to create new zone (type in some friendly name of zone in that case - that will not be visible anywhere except your AWS control panel)</li>
58
- <li>In a distribution setup form you will be notified with the settings required. Tou have only 1 editable field is alternative hostname of your Wordpress host. For example if your have myblog.com website with A record pointint to 1.2.3.4 IP, create another one origin.myblog.com DNS record with A record pointint to 1.2.3.4 IP and type in "origin.myblog.com" in this form.</li>
59
- <li>You get success page with information about DNS changes. Now you need to change record of your wordpress host from IP address and replace it to CNAME to specified hostname.</li>
60
- <li>It works</li>
61
- </ol>
62
- </p>
63
- ]]></answer>
64
- </entry>
65
- <entry>
66
- <question><![CDATA[ How do I get CloudFront Dynamic Caching to work with full site delivery (FSD)? ]]></question>
67
- <answer><![CDATA[
68
- <p>
69
- First enable Browser Cache and disable "Expires" header. This is because CloudFront does not cache properly
70
- when "Expires" headers are set. When using CloudFront and full page caching there are no purging of cached pages when posting
71
- new posts etc. Cache invalidations in CF is limited per month and also takes up to 15 minutes to complete. </p>
72
- <p>Since there is no purging and you want to people to be able to comment it is recommended to use a hosted
73
- commenting software, such as FaceBook Comments or Disqus. If you do not use this comments are not
74
- shown after they been posted or approved.
75
- </p>
76
- <p>
77
- Main step to get CloudFront full page caching working is to have your site on a different domain than the
78
- one you want your visitors to see. So you should install or configure your site so its on a separate domain,
79
- for example wp.example.com. You will then later configure example.com so its used by CloudFront.
80
- </p>
81
- <p>How to configure CloudFront on AWS:</p>
82
- <ol>
83
- <li>Go to <a href="https://console.aws.amazon.com/cloudfront/home">AWS Console</a></li>
84
- <li>Click "Create Distribution"</li>
85
- <li>Select "Web"</li>
86
- <li>Click "Continue"</li>
87
- <li>Enter wp.example.com into "Origin Domain Name"</li>
88
- <li>Enter CustomWWW-example.com into "Origin ID"</li>
89
- <li>Set Origin Protocol Policy to HTTP Only (CloudFront will connect to my origin using only HTTP).</li>
90
- <li>Select "Allow HTTP Methods" - GET, HEAD, PUT, PATCH, DELETE, OPTIONS</li>
91
- <li>Select "Forward Query Strings" - Yes</li>
92
- <li>Enter example.com (the domain that your visitors will type into their browser) into
93
- Alternate Domain Names(CNAMESs)</li>
94
- <li>Set logging to "On"</li>
95
- <li>Enter "webserverlog-example.com" into "Bucket for logs"</li>
96
- <li>Enter "stats-logs/" into Log Prefix</li>
97
- <li>Enter "CDN for example.com" into Comment.</li>
98
- <li>Click "Create Distribution"</li>
99
- </ol>
100
- <p>Configure DNS</p>
101
- <ol>
102
- <li>Add new CNAME recored for example.com that points to the Domain Name that belongs to the distribution you created previously.
103
- </ol>
104
- <p>How to configure W3 Total Cache:</p>
105
- <p>There are two methods to configure W3 Total Cache CDN. Origin Pull "CloudFront" or "Generic mirror". If you want to be able to invalidate URLs from within WordPress you need to use the CloudFront option.
106
- If you do not configure an CDN the wrong URLs will be used when linking to CSS, JS and other files.
107
- </p>
108
- <p>Configure CloudFront:</p>
109
- <ol>
110
- <li>Select Origin Pull (Mirror) Amazon CloudPront on General Page</li>
111
- <li>Go to the CDN page.</li>
112
- <li>Enter your AWS credentials</li>
113
- <li>Enter example.com as an CNAME</li>
114
- <li>Save Settings</li>
115
- </ol>
116
- <p>Configure Generic Mirror:</p>
117
- <ol>
118
- <li>Enter example.com into "Replace site's hostname with:"</li>
119
- <li>Save Settings</li>
120
- </ol>
121
- ]]>
122
- </answer>
123
- </entry>
124
- </section>
125
- <section name="Extensions">
126
- <entry>
127
- <question><![CDATA[ What is required for the Genesis Extension to work? ]]></question>
128
- <answer><![CDATA[ <p>You need to enable Fragment Caching and use a theme based on Genesis.</p> ]]></answer>
129
- </entry>
130
 
131
- <entry>
132
- <question><![CDATA[ When I enabled Genesis Extension with EDD, WooCommerce or other similar plugins, my cart,
133
- checkout and/or other dynamic elements no longer get updated. How do I fix that? ]]></question>
134
- <answer><![CDATA[
135
- <p>You need to go the Genesis Extension settings page.
136
- There you will a textbox called "Excluded single pages / posts:" there you need to enter the pages
137
- that should not be cached by the fragment caching. The exclude textareas support regular expressions
138
- so if the pages that are to be excluded are similar you can most likely enter one
139
- expression that covers all your pages. For information on regular expression you need to search.</p>
140
- <p>
141
- If you have anything dynamic in your widgets area, the sidebar, then you'll need to disable the sidebar caching, or enter pages that should not have their sidedar cached.
142
- </p>
143
- ]]></answer>
144
- </entry>
145
- </section>
146
- </section>
147
- <section name="Developers">
148
- <entry>
149
- <question><![CDATA[ How do I implement fragment caching? ]]></question>
150
- <answer><![CDATA[
151
  <p>Fragment caching adds new functionality to the WordPress <a href="http://codex.wordpress.org/Transients_API">Transients <acronym title="Application Programming Interface">API</acronym></a>:</p>
152
  <ul>
153
- <li>Adds support for grouping transients both per blog and site wide</li>
154
- <li>Adds support for manual flushing of registered transient groups</li>
155
- <li>Adds support for action based flushing of registered transient groups</li>
156
- <li>Adds support for caching filters and actions</li>
157
  </ul>
158
  <p>To make the plugin aware that you group transients see code examples below:</p>
159
  <pre>
160
- add_action('w3tc_register_fragment_groups', 'my_plugin_register_groups');
161
 
162
- function my_plugin_register_groups() {
163
- //blog specific group and an array of actions that will trigger a flush of the group
164
- w3tc_register_fragment_group('my_plugin_', array('publish_post'), 3600);
165
- //If using MultiSite Network/site wide specific group and an array of actions that will trigger a flush of the group
166
- w3tc_register_fragment_group_global('my_plugin_global_', array('edit_site'), 3600);
167
- }
168
- function my_plugin_flush_group() {
169
- //manually flush group.
170
- w3tc_fragmentcache_flush_group('my_plugin_');
171
- }
172
 
173
- //Set transients
174
- function on_some_event() {
175
- if (false === get_transient('my_plugin_some_key'))
176
- //my_plugin_ prefix is the group name we registered earlier
177
- set_transient('my_plugin_some_key', 'blog specific value');
178
- if (false === get_site_transient('my_plugin_some_key'))
179
- //my_plugin_site_ prefix is the group name we registered earlier
180
- set_site_transient('my_plugin_site_some_key', 'site wide specific value');
181
- }
182
 
183
- // Cache action example
184
- add_action('theme_post_loop', 'cache_theme_post_loop_start',-999999999);
185
- add_action('theme_post_loop', 'cache_theme_post_loop_end', 999999999);
186
 
187
- /**
188
- * Start outputbuffering
189
- */
190
- function cache_theme_post_loop_start() {
191
- w3tc_fragmentcache_start('example1', 'examples', 'theme_post_loop');
192
- }
193
 
194
- /**
195
- * Store the output buffer .
196
- */
197
- function cache_theme_post_loop_end() {
198
- w3tc_fragmentcache_end('example1', 'examples', false);
199
- }
200
 
201
- // Cache filter example
202
- add_filter('theme_filter', 'cache_theme_filter_start',-999999999);
203
- add_filter('theme_filter', 'cache_theme_filter_end', 999999999);
204
- /**
205
- * Start filter buffering and return filter result
206
- */
207
- function cache_theme_filter_start($data) {
208
- return w3tc_fragmentcache_filter_start('example_filter1', 'examples', $hook, $data);
209
- }
210
 
211
- /**
212
- * Store the filter result and return filter result.
213
- */
214
- function cache_theme_filter_end($data) {
215
- return w3tc_fragmentcache_filter_end('example_filter1', 'examples', $data);
216
- }
217
- </pre>
218
  ]]></answer>
219
- </entry>
220
- </section>
221
  </faqs>
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <faqs>
3
+ <section name="General">
4
+ <entry>
5
+ <question>
6
+ <![CDATA[ Which Pro features are currently available? ]]>
7
+ </question>
8
+ <answer>
9
+ <![CDATA[ <p>Pro features available:</p>
10
+ <ul>
11
+ <li>Fragment Cache Extension</li>
12
+ <li>Genesis Extension</li>
13
+ <li>WPML Extension</li>
14
+ <li>Full Site Delivery (FSD)</li>
15
+ <li>Cache Statistics</li>
16
+ </ul>
17
+ ]]>
18
+ </answer>
19
+ </entry>
20
+ <entry>
21
+ <question><![CDATA[ How do I enable Pro mode on a site that is not registered, i.e a site that was not used for purchase such as local development site?]]></question>
22
+ <answer><![CDATA[
23
+ <p>Add define('W3TC_PRO_DEV_MODE', true) to wp-config.php and resave the license key.</p>
24
+ ]]></answer>
25
+ </entry>
26
+ </section>
27
+ <section name="Usage">
28
+ <section name="CDN">
29
+ <entry>
30
+ <tag>cdn-fsd-maxcdn</tag>
31
+ <question><![CDATA[ How do I set up Full Site Delivery (FSD) with MaxCDN? ]]></question>
32
+ <answer><![CDATA[
33
+ <p>
34
+ <ol>
35
+ <li>Select CDN provider of your choice in a "Full site mirroring" group of "CDN type" dropdown on "General Settings" page, select MaxCDN there.</li>
36
+ <li>Go to "CDN" page.</li>
37
+ <li>Click "Authorize" button</li>
38
+ <li>Type in API key of your account. You can obtain by following a link in a popup. Opening that link will you will be prompted for your MaxCDN login and password.
39
+ Select Zone from the list or choose "Add new" to create new zone (type in some friendly name of zone in that case)</li>
40
+ <li>In a zone setup form you will be notified with the settings required for zone. Tou have only 1 editable field is IP address of your WordPress host. W3 Total Cache tries to guess it, but its not possible to know that in all possible cases.</li>
41
+ <li>You get success page with information about DNS changes. Now you need to change record of your wordpress host from IP address and replace it to CNAME to specified hostname.</li>
42
+ <li>It works</li>
43
+ </ol>
44
+ </p>
45
+ ]]></answer>
46
+ </entry>
47
+ <entry>
48
+ <tag>cdn-fsd-cloudfront</tag>
49
+ <question><![CDATA[ How do I set up Full Site Delivery (FSD) with CloudFront? ]]></question>
50
+ <answer><![CDATA[
51
+ <p>
52
+ <ol>
53
+ <li>Select CDN provider of your choice in a "Full site mirroring" group of "CDN type" dropdown on "General Settings" page, select CloudFront there.</li>
54
+ <li>Go to "CDN" page.</li>
55
+ <li>Click "Authorize" button</li>
56
+ <li>Type in Access Key and Secret Key of your account.</li>
57
+ <li>Select Distribution from the list or choose "Add new" to create new zone (type in some friendly name of zone in that case - that will not be visible anywhere except your AWS control panel)</li>
58
+ <li>In a distribution setup form you will be notified with the settings required. Tou have only 1 editable field is alternative hostname of your WordPress host. For example if your have myblog.com website with A record pointint to 1.2.3.4 IP, create another one origin.myblog.com DNS record with A record pointint to 1.2.3.4 IP and type in "origin.myblog.com" in this form.</li>
59
+ <li>You get success page with information about DNS changes. Now you need to change record of your wordpress host from IP address and replace it to CNAME to specified hostname.</li>
60
+ <li>It works</li>
61
+ </ol>
62
+ </p>
63
+ ]]></answer>
64
+ </entry>
65
+ <entry>
66
+ <question><![CDATA[ How do I get CloudFront Dynamic Caching to work with full site delivery (FSD)? ]]></question>
67
+ <answer><![CDATA[
68
+ <p>
69
+ First enable Browser Cache and disable "Expires" header. This is because CloudFront does not cache properly
70
+ when "Expires" headers are set. When using CloudFront and full page caching there are no purging of cached pages when posting
71
+ new posts etc. Cache invalidations in CF is limited per month and also takes up to 15 minutes to complete. </p>
72
+ <p>Since there is no purging and you want to people to be able to comment it is recommended to use a hosted
73
+ commenting software, such as FaceBook Comments or Disqus. If you do not use this comments are not
74
+ shown after they been posted or approved.
75
+ </p>
76
+ <p>
77
+ Main step to get CloudFront full page caching working is to have your site on a different domain than the
78
+ one you want your visitors to see. So you should install or configure your site so its on a separate domain,
79
+ for example wp.example.com. You will then later configure example.com so its used by CloudFront.
80
+ </p>
81
+ <p>How to configure CloudFront on AWS:</p>
82
+ <ol>
83
+ <li>Go to <a href="https://console.aws.amazon.com/cloudfront/home">AWS Console</a></li>
84
+ <li>Click "Create Distribution"</li>
85
+ <li>Select "Web"</li>
86
+ <li>Click "Continue"</li>
87
+ <li>Enter wp.example.com into "Origin Domain Name"</li>
88
+ <li>Enter CustomWWW-example.com into "Origin ID"</li>
89
+ <li>Set Origin Protocol Policy to HTTP Only (CloudFront will connect to my origin using only HTTP).</li>
90
+ <li>Select "Allow HTTP Methods" - GET, HEAD, PUT, PATCH, DELETE, OPTIONS</li>
91
+ <li>Select "Forward Query Strings" - Yes</li>
92
+ <li>Enter example.com (the domain that your visitors will type into their browser) into
93
+ Alternate Domain Names(CNAMESs)</li>
94
+ <li>Set logging to "On"</li>
95
+ <li>Enter "webserverlog-example.com" into "Bucket for logs"</li>
96
+ <li>Enter "stats-logs/" into Log Prefix</li>
97
+ <li>Enter "CDN for example.com" into Comment.</li>
98
+ <li>Click "Create Distribution"</li>
99
+ </ol>
100
+ <p>Configure DNS</p>
101
+ <ol>
102
+ <li>Add new CNAME recored for example.com that points to the Domain Name that belongs to the distribution you created previously.
103
+ </ol>
104
+ <p>How to configure W3 Total Cache:</p>
105
+ <p>There are two methods to configure W3 Total Cache CDN. Origin Pull "CloudFront" or "Generic mirror". If you want to be able to invalidate URLs from within WordPress you need to use the CloudFront option.
106
+ If you do not configure an CDN the wrong URLs will be used when linking to CSS, JS and other files.
107
+ </p>
108
+ <p>Configure CloudFront:</p>
109
+ <ol>
110
+ <li>Select Origin Pull (Mirror) Amazon CloudPront on General Page</li>
111
+ <li>Go to the CDN page.</li>
112
+ <li>Enter your AWS credentials</li>
113
+ <li>Enter example.com as an CNAME</li>
114
+ <li>Save Settings</li>
115
+ </ol>
116
+ <p>Configure Generic Mirror:</p>
117
+ <ol>
118
+ <li>Enter example.com into "Replace site's hostname with:"</li>
119
+ <li>Save Settings</li>
120
+ </ol>
121
+ ]]>
122
+ </answer>
123
+ </entry>
124
+ </section>
125
+ <section name="Extensions">
126
+ <entry>
127
+ <question><![CDATA[ What is required for the Genesis Extension to work? ]]></question>
128
+ <answer><![CDATA[ <p>You need to enable Fragment Caching and use a theme based on Genesis.</p> ]]></answer>
129
+ </entry>
130
 
131
+ <entry>
132
+ <question><![CDATA[ When I enabled Genesis Extension with EDD, WooCommerce or other similar plugins, my cart,
133
+ checkout and/or other dynamic elements no longer get updated. How do I fix that? ]]></question>
134
+ <answer><![CDATA[
135
+ <p>You need to go the Genesis Extension settings page.
136
+ There you will a textbox called "Excluded single pages / posts:" there you need to enter the pages
137
+ that should not be cached by the fragment caching. The exclude textareas support regular expressions
138
+ so if the pages that are to be excluded are similar you can most likely enter one
139
+ expression that covers all your pages. For information on regular expression you need to search.</p>
140
+ <p>
141
+ If you have anything dynamic in your widgets area, the sidebar, then you'll need to disable the sidebar caching, or enter pages that should not have their sidedar cached.
142
+ </p>
143
+ ]]></answer>
144
+ </entry>
145
+ </section>
146
+ </section>
147
+ <section name="Developers">
148
+ <entry>
149
+ <question><![CDATA[ How do I implement fragment caching? ]]></question>
150
+ <answer><![CDATA[
151
  <p>Fragment caching adds new functionality to the WordPress <a href="http://codex.wordpress.org/Transients_API">Transients <acronym title="Application Programming Interface">API</acronym></a>:</p>
152
  <ul>
153
+ <li>Adds support for grouping transients both per blog and site wide</li>
154
+ <li>Adds support for manual flushing of registered transient groups</li>
155
+ <li>Adds support for action based flushing of registered transient groups</li>
156
+ <li>Adds support for caching filters and actions</li>
157
  </ul>
158
  <p>To make the plugin aware that you group transients see code examples below:</p>
159
  <pre>
160
+ add_action('w3tc_register_fragment_groups', 'my_plugin_register_groups');
161
 
162
+ function my_plugin_register_groups() {
163
+ //blog specific group and an array of actions that will trigger a flush of the group
164
+ w3tc_register_fragment_group('my_plugin_', array('publish_post'), 3600);
165
+ //If using MultiSite Network/site wide specific group and an array of actions that will trigger a flush of the group
166
+ w3tc_register_fragment_group_global('my_plugin_global_', array('edit_site'), 3600);
167
+ }
168
+ function my_plugin_flush_group() {
169
+ //manually flush group.
170
+ w3tc_fragmentcache_flush_group('my_plugin_');
171
+ }
172
 
173
+ //Set transients
174
+ function on_some_event() {
175
+ if (false === get_transient('my_plugin_some_key'))
176
+ //my_plugin_ prefix is the group name we registered earlier
177
+ set_transient('my_plugin_some_key', 'blog specific value');
178
+ if (false === get_site_transient('my_plugin_some_key'))
179
+ //my_plugin_site_ prefix is the group name we registered earlier
180
+ set_site_transient('my_plugin_site_some_key', 'site wide specific value');
181
+ }
182
 
183
+ // Cache action example
184
+ add_action('theme_post_loop', 'cache_theme_post_loop_start',-999999999);
185
+ add_action('theme_post_loop', 'cache_theme_post_loop_end', 999999999);
186
 
187
+ /**
188
+ * Start outputbuffering
189
+ */
190
+ function cache_theme_post_loop_start() {
191
+ w3tc_fragmentcache_start('example1', 'examples', 'theme_post_loop');
192
+ }
193
 
194
+ /**
195
+ * Store the output buffer .
196
+ */
197
+ function cache_theme_post_loop_end() {
198
+ w3tc_fragmentcache_end('example1', 'examples', false);
199
+ }
200
 
201
+ // Cache filter example
202
+ add_filter('theme_filter', 'cache_theme_filter_start',-999999999);
203
+ add_filter('theme_filter', 'cache_theme_filter_end', 999999999);
204
+ /**
205
+ * Start filter buffering and return filter result
206
+ */
207
+ function cache_theme_filter_start($data) {
208
+ return w3tc_fragmentcache_filter_start('example_filter1', 'examples', $hook, $data);
209
+ }
210
 
211
+ /**
212
+ * Store the filter result and return filter result.
213
+ */
214
+ function cache_theme_filter_end($data) {
215
+ return w3tc_fragmentcache_filter_end('example_filter1', 'examples', $data);
216
+ }
217
+ </pre>
218
  ]]></answer>
219
+ </entry>
220
+ </section>
221
  </faqs>
languages/w3-total-cache-ar_AR.po CHANGED
@@ -2934,7 +2934,7 @@ msgid "Specify user agents that will never receive minified content."
2934
  msgstr ""
2935
 
2936
  #: inc/options/minify.php:485
2937
- msgid "Include external files/libaries:"
2938
  msgstr ""
2939
 
2940
  #: inc/options/minify.php:490
2934
  msgstr ""
2935
 
2936
  #: inc/options/minify.php:485
2937
+ msgid "Include external files/libraries:"
2938
  msgstr ""
2939
 
2940
  #: inc/options/minify.php:490
languages/w3-total-cache-nl_NL.po CHANGED
@@ -2932,7 +2932,7 @@ msgid "Specify user agents that will never receive minified content."
2932
  msgstr ""
2933
 
2934
  #: ../inc/options/minify.php:485
2935
- msgid "Include external files/libaries:"
2936
  msgstr ""
2937
 
2938
  #: ../inc/options/minify.php:490
2932
  msgstr ""
2933
 
2934
  #: ../inc/options/minify.php:485
2935
+ msgid "Include external files/libraries:"
2936
  msgstr ""
2937
 
2938
  #: ../inc/options/minify.php:490
languages/w3-total-cache-pl_PL.po CHANGED
@@ -2928,7 +2928,7 @@ msgid "Specify user agents that will never receive minified content."
2928
  msgstr ""
2929
 
2930
  #: inc/options/minify.php:485
2931
- msgid "Include external files/libaries:"
2932
  msgstr ""
2933
 
2934
  #: inc/options/minify.php:490
2928
  msgstr ""
2929
 
2930
  #: inc/options/minify.php:485
2931
+ msgid "Include external files/libraries:"
2932
  msgstr ""
2933
 
2934
  #: inc/options/minify.php:490
languages/w3-total-cache-sr_RS.po CHANGED
@@ -3454,7 +3454,7 @@ msgstr ""
3454
  "Navedite korisničke agente koji nikada neće dobiti minifikovani sadržaj."
3455
 
3456
  #: ../inc/options/minify.php:485
3457
- msgid "Include external files/libaries:"
3458
  msgstr "Uključiti eksterne fajlove/biblioteke:"
3459
 
3460
  #: ../inc/options/minify.php:490
3454
  "Navedite korisničke agente koji nikada neće dobiti minifikovani sadržaj."
3455
 
3456
  #: ../inc/options/minify.php:485
3457
+ msgid "Include external files/libraries:"
3458
  msgstr "Uključiti eksterne fajlove/biblioteke:"
3459
 
3460
  #: ../inc/options/minify.php:490
lib/Azure/GuzzleHttp/Client.php ADDED
@@ -0,0 +1,408 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Cookie\CookieJar;
5
+ use GuzzleHttp\Promise;
6
+ use GuzzleHttp\Psr7;
7
+ use Psr\Http\Message\UriInterface;
8
+ use Psr\Http\Message\RequestInterface;
9
+ use Psr\Http\Message\ResponseInterface;
10
+
11
+ /**
12
+ * @method ResponseInterface get(string|UriInterface $uri, array $options = [])
13
+ * @method ResponseInterface head(string|UriInterface $uri, array $options = [])
14
+ * @method ResponseInterface put(string|UriInterface $uri, array $options = [])
15
+ * @method ResponseInterface post(string|UriInterface $uri, array $options = [])
16
+ * @method ResponseInterface patch(string|UriInterface $uri, array $options = [])
17
+ * @method ResponseInterface delete(string|UriInterface $uri, array $options = [])
18
+ * @method Promise\PromiseInterface getAsync(string|UriInterface $uri, array $options = [])
19
+ * @method Promise\PromiseInterface headAsync(string|UriInterface $uri, array $options = [])
20
+ * @method Promise\PromiseInterface putAsync(string|UriInterface $uri, array $options = [])
21
+ * @method Promise\PromiseInterface postAsync(string|UriInterface $uri, array $options = [])
22
+ * @method Promise\PromiseInterface patchAsync(string|UriInterface $uri, array $options = [])
23
+ * @method Promise\PromiseInterface deleteAsync(string|UriInterface $uri, array $options = [])
24
+ */
25
+ class Client implements ClientInterface
26
+ {
27
+ /** @var array Default request options */
28
+ private $config;
29
+
30
+ /**
31
+ * Clients accept an array of constructor parameters.
32
+ *
33
+ * Here's an example of creating a client using a base_uri and an array of
34
+ * default request options to apply to each request:
35
+ *
36
+ * $client = new Client([
37
+ * 'base_uri' => 'http://www.foo.com/1.0/',
38
+ * 'timeout' => 0,
39
+ * 'allow_redirects' => false,
40
+ * 'proxy' => '192.168.16.1:10'
41
+ * ]);
42
+ *
43
+ * Client configuration settings include the following options:
44
+ *
45
+ * - handler: (callable) Function that transfers HTTP requests over the
46
+ * wire. The function is called with a Psr7\Http\Message\RequestInterface
47
+ * and array of transfer options, and must return a
48
+ * GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
49
+ * Psr7\Http\Message\ResponseInterface on success. "handler" is a
50
+ * constructor only option that cannot be overridden in per/request
51
+ * options. If no handler is provided, a default handler will be created
52
+ * that enables all of the request options below by attaching all of the
53
+ * default middleware to the handler.
54
+ * - base_uri: (string|UriInterface) Base URI of the client that is merged
55
+ * into relative URIs. Can be a string or instance of UriInterface.
56
+ * - **: any request option
57
+ *
58
+ * @param array $config Client configuration settings.
59
+ *
60
+ * @see \GuzzleHttp\RequestOptions for a list of available request options.
61
+ */
62
+ public function __construct(array $config = [])
63
+ {
64
+ if (!isset($config['handler'])) {
65
+ $config['handler'] = HandlerStack::create();
66
+ }
67
+
68
+ // Convert the base_uri to a UriInterface
69
+ if (isset($config['base_uri'])) {
70
+ $config['base_uri'] = Psr7\uri_for($config['base_uri']);
71
+ }
72
+
73
+ $this->configureDefaults($config);
74
+ }
75
+
76
+ public function __call($method, $args)
77
+ {
78
+ if (count($args) < 1) {
79
+ throw new \InvalidArgumentException('Magic request methods require a URI and optional options array');
80
+ }
81
+
82
+ $uri = $args[0];
83
+ $opts = isset($args[1]) ? $args[1] : [];
84
+
85
+ return substr($method, -5) === 'Async'
86
+ ? $this->requestAsync(substr($method, 0, -5), $uri, $opts)
87
+ : $this->request($method, $uri, $opts);
88
+ }
89
+
90
+ public function sendAsync(RequestInterface $request, array $options = [])
91
+ {
92
+ // Merge the base URI into the request URI if needed.
93
+ $options = $this->prepareDefaults($options);
94
+
95
+ return $this->transfer(
96
+ $request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')),
97
+ $options
98
+ );
99
+ }
100
+
101
+ public function send(RequestInterface $request, array $options = [])
102
+ {
103
+ $options[RequestOptions::SYNCHRONOUS] = true;
104
+ return $this->sendAsync($request, $options)->wait();
105
+ }
106
+
107
+ public function requestAsync($method, $uri = '', array $options = [])
108
+ {
109
+ $options = $this->prepareDefaults($options);
110
+ // Remove request modifying parameter because it can be done up-front.
111
+ $headers = isset($options['headers']) ? $options['headers'] : [];
112
+ $body = isset($options['body']) ? $options['body'] : null;
113
+ $version = isset($options['version']) ? $options['version'] : '1.1';
114
+ // Merge the URI into the base URI.
115
+ $uri = $this->buildUri($uri, $options);
116
+ if (is_array($body)) {
117
+ $this->invalidBody();
118
+ }
119
+ $request = new Psr7\Request($method, $uri, $headers, $body, $version);
120
+ // Remove the option so that they are not doubly-applied.
121
+ unset($options['headers'], $options['body'], $options['version']);
122
+
123
+ return $this->transfer($request, $options);
124
+ }
125
+
126
+ public function request($method, $uri = '', array $options = [])
127
+ {
128
+ $options[RequestOptions::SYNCHRONOUS] = true;
129
+ return $this->requestAsync($method, $uri, $options)->wait();
130
+ }
131
+
132
+ public function getConfig($option = null)
133
+ {
134
+ return $option === null
135
+ ? $this->config
136
+ : (isset($this->config[$option]) ? $this->config[$option] : null);
137
+ }
138
+
139
+ private function buildUri($uri, array $config)
140
+ {
141
+ // for BC we accept null which would otherwise fail in uri_for
142
+ $uri = Psr7\uri_for($uri === null ? '' : $uri);
143
+
144
+ if (isset($config['base_uri'])) {
145
+ $uri = Psr7\Uri::resolve(Psr7\uri_for($config['base_uri']), $uri);
146
+ }
147
+
148
+ return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
149
+ }
150
+
151
+ /**
152
+ * Configures the default options for a client.
153
+ *
154
+ * @param array $config
155
+ */
156
+ private function configureDefaults(array $config)
157
+ {
158
+ $defaults = [
159
+ 'allow_redirects' => RedirectMiddleware::$defaultSettings,
160
+ 'http_errors' => true,
161
+ 'decode_content' => true,
162
+ 'verify' => true,
163
+ 'cookies' => false
164
+ ];
165
+
166
+ // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
167
+
168
+ // We can only trust the HTTP_PROXY environment variable in a CLI
169
+ // process due to the fact that PHP has no reliable mechanism to
170
+ // get environment variables that start with "HTTP_".
171
+ if (php_sapi_name() == 'cli' && getenv('HTTP_PROXY')) {
172
+ $defaults['proxy']['http'] = getenv('HTTP_PROXY');
173
+ }
174
+
175
+ if ($proxy = getenv('HTTPS_PROXY')) {
176
+ $defaults['proxy']['https'] = $proxy;
177
+ }
178
+
179
+ if ($noProxy = getenv('NO_PROXY')) {
180
+ $cleanedNoProxy = str_replace(' ', '', $noProxy);
181
+ $defaults['proxy']['no'] = explode(',', $cleanedNoProxy);
182
+ }
183
+
184
+ $this->config = $config + $defaults;
185
+
186
+ if (!empty($config['cookies']) && $config['cookies'] === true) {
187
+ $this->config['cookies'] = new CookieJar();
188
+ }
189
+
190
+ // Add the default user-agent header.
191
+ if (!isset($this->config['headers'])) {
192
+ $this->config['headers'] = ['User-Agent' => default_user_agent()];
193
+ } else {
194
+ // Add the User-Agent header if one was not already set.
195
+ foreach (array_keys($this->config['headers']) as $name) {
196
+ if (strtolower($name) === 'user-agent') {
197
+ return;
198
+ }
199
+ }
200
+ $this->config['headers']['User-Agent'] = default_user_agent();
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Merges default options into the array.
206
+ *
207
+ * @param array $options Options to modify by reference
208
+ *
209
+ * @return array
210
+ */
211
+ private function prepareDefaults($options)
212
+ {
213
+ $defaults = $this->config;
214
+
215
+ if (!empty($defaults['headers'])) {
216
+ // Default headers are only added if they are not present.
217
+ $defaults['_conditional'] = $defaults['headers'];
218
+ unset($defaults['headers']);
219
+ }
220
+
221
+ // Special handling for headers is required as they are added as
222
+ // conditional headers and as headers passed to a request ctor.
223
+ if (array_key_exists('headers', $options)) {
224
+ // Allows default headers to be unset.
225
+ if ($options['headers'] === null) {
226
+ $defaults['_conditional'] = null;
227
+ unset($options['headers']);
228
+ } elseif (!is_array($options['headers'])) {
229
+ throw new \InvalidArgumentException('headers must be an array');
230
+ }
231
+ }
232
+
233
+ // Shallow merge defaults underneath options.
234
+ $result = $options + $defaults;
235
+
236
+ // Remove null values.
237
+ foreach ($result as $k => $v) {
238
+ if ($v === null) {
239
+ unset($result[$k]);
240
+ }
241
+ }
242
+
243
+ return $result;
244
+ }
245
+
246
+ /**
247
+ * Transfers the given request and applies request options.
248
+ *
249
+ * The URI of the request is not modified and the request options are used
250
+ * as-is without merging in default options.
251
+ *
252
+ * @param RequestInterface $request
253
+ * @param array $options
254
+ *
255
+ * @return Promise\PromiseInterface
256
+ */
257
+ private function transfer(RequestInterface $request, array $options)
258
+ {
259
+ // save_to -> sink
260
+ if (isset($options['save_to'])) {
261
+ $options['sink'] = $options['save_to'];
262
+ unset($options['save_to']);
263
+ }
264
+
265
+ // exceptions -> http_errors
266
+ if (isset($options['exceptions'])) {
267
+ $options['http_errors'] = $options['exceptions'];
268
+ unset($options['exceptions']);
269
+ }
270
+
271
+ $request = $this->applyOptions($request, $options);
272
+ $handler = $options['handler'];
273
+
274
+ try {
275
+ return Promise\promise_for($handler($request, $options));
276
+ } catch (\Exception $e) {
277
+ return Promise\rejection_for($e);
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Applies the array of request options to a request.
283
+ *
284
+ * @param RequestInterface $request
285
+ * @param array $options
286
+ *
287
+ * @return RequestInterface
288
+ */
289
+ private function applyOptions(RequestInterface $request, array &$options)
290
+ {
291
+ $modify = [];
292
+
293
+ if (isset($options['form_params'])) {
294
+ if (isset($options['multipart'])) {
295
+ throw new \InvalidArgumentException('You cannot use '
296
+ . 'form_params and multipart at the same time. Use the '
297
+ . 'form_params option if you want to send application/'
298
+ . 'x-www-form-urlencoded requests, and the multipart '
299
+ . 'option to send multipart/form-data requests.');
300
+ }
301
+ $options['body'] = http_build_query($options['form_params'], '', '&');
302
+ unset($options['form_params']);
303
+ $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
304
+ }
305
+
306
+ if (isset($options['multipart'])) {
307
+ $options['body'] = new Psr7\MultipartStream($options['multipart']);
308
+ unset($options['multipart']);
309
+ }
310
+
311
+ if (isset($options['json'])) {
312
+ $options['body'] = \GuzzleHttp\json_encode($options['json']);
313
+ unset($options['json']);
314
+ $options['_conditional']['Content-Type'] = 'application/json';
315
+ }
316
+
317
+ if (!empty($options['decode_content'])
318
+ && $options['decode_content'] !== true
319
+ ) {
320
+ $modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
321
+ }
322
+
323
+ if (isset($options['headers'])) {
324
+ if (isset($modify['set_headers'])) {
325
+ $modify['set_headers'] = $options['headers'] + $modify['set_headers'];
326
+ } else {
327
+ $modify['set_headers'] = $options['headers'];
328
+ }
329
+ unset($options['headers']);
330
+ }
331
+
332
+ if (isset($options['body'])) {
333
+ if (is_array($options['body'])) {
334
+ $this->invalidBody();
335
+ }
336
+ $modify['body'] = Psr7\stream_for($options['body']);
337
+ unset($options['body']);
338
+ }
339
+
340
+ if (!empty($options['auth']) && is_array($options['auth'])) {
341
+ $value = $options['auth'];
342
+ $type = isset($value[2]) ? strtolower($value[2]) : 'basic';
343
+ switch ($type) {
344
+ case 'basic':
345
+ $modify['set_headers']['Authorization'] = 'Basic '
346
+ . base64_encode("$value[0]:$value[1]");
347
+ break;
348
+ case 'digest':
349
+ // @todo: Do not rely on curl
350
+ $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_DIGEST;
351
+ $options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
352
+ break;
353
+ }
354
+ }
355
+
356
+ if (isset($options['query'])) {
357
+ $value = $options['query'];
358
+ if (is_array($value)) {
359
+ $value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);
360
+ }
361
+ if (!is_string($value)) {
362
+ throw new \InvalidArgumentException('query must be a string or array');
363
+ }
364
+ $modify['query'] = $value;
365
+ unset($options['query']);
366
+ }
367
+
368
+ // Ensure that sink is not an invalid value.
369
+ if (isset($options['sink'])) {
370
+ // TODO: Add more sink validation?
371
+ if (is_bool($options['sink'])) {
372
+ throw new \InvalidArgumentException('sink must not be a boolean');
373
+ }
374
+ }
375
+
376
+ $request = Psr7\modify_request($request, $modify);
377
+ if ($request->getBody() instanceof Psr7\MultipartStream) {
378
+ // Use a multipart/form-data POST if a Content-Type is not set.
379
+ $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
380
+ . $request->getBody()->getBoundary();
381
+ }
382
+
383
+ // Merge in conditional headers if they are not present.
384
+ if (isset($options['_conditional'])) {
385
+ // Build up the changes so it's in a single clone of the message.
386
+ $modify = [];
387
+ foreach ($options['_conditional'] as $k => $v) {
388
+ if (!$request->hasHeader($k)) {
389
+ $modify['set_headers'][$k] = $v;
390
+ }
391
+ }
392
+ $request = Psr7\modify_request($request, $modify);
393
+ // Don't pass this internal value along to middleware/handlers.
394
+ unset($options['_conditional']);
395
+ }
396
+
397
+ return $request;
398
+ }
399
+
400
+ private function invalidBody()
401
+ {
402
+ throw new \InvalidArgumentException('Passing in the "body" request '
403
+ . 'option as an array to send a POST request has been deprecated. '
404
+ . 'Please use the "form_params" request option to send a '
405
+ . 'application/x-www-form-urlencoded request, or a the "multipart" '
406
+ . 'request option to send a multipart/form-data request.');
407
+ }
408
+ }
lib/Azure/GuzzleHttp/ClientInterface.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Promise\PromiseInterface;
5
+ use GuzzleHttp\Exception\GuzzleException;
6
+ use Psr\Http\Message\RequestInterface;
7
+ use Psr\Http\Message\ResponseInterface;
8
+ use Psr\Http\Message\UriInterface;
9
+
10
+ /**
11
+ * Client interface for sending HTTP requests.
12
+ */
13
+ interface ClientInterface
14
+ {
15
+ const VERSION = '6.2.1';
16
+
17
+ /**
18
+ * Send an HTTP request.
19
+ *
20
+ * @param RequestInterface $request Request to send
21
+ * @param array $options Request options to apply to the given
22
+ * request and to the transfer.
23
+ *
24
+ * @return ResponseInterface
25
+ * @throws GuzzleException
26
+ */
27
+ public function send(RequestInterface $request, array $options = []);
28
+
29
+ /**
30
+ * Asynchronously send an HTTP request.
31
+ *
32
+ * @param RequestInterface $request Request to send
33
+ * @param array $options Request options to apply to the given
34
+ * request and to the transfer.
35
+ *
36
+ * @return PromiseInterface
37
+ */
38
+ public function sendAsync(RequestInterface $request, array $options = []);
39
+
40
+ /**
41
+ * Create and send an HTTP request.
42
+ *
43
+ * Use an absolute path to override the base path of the client, or a
44
+ * relative path to append to the base path of the client. The URL can
45
+ * contain the query string as well.
46
+ *
47
+ * @param string $method HTTP method.
48
+ * @param string|UriInterface $uri URI object or string.
49
+ * @param array $options Request options to apply.
50
+ *
51
+ * @return ResponseInterface
52
+ * @throws GuzzleException
53
+ */
54
+ public function request($method, $uri, array $options = []);
55
+
56
+ /**
57
+ * Create and send an asynchronous HTTP request.
58
+ *
59
+ * Use an absolute path to override the base path of the client, or a
60
+ * relative path to append to the base path of the client. The URL can
61
+ * contain the query string as well. Use an array to provide a URL
62
+ * template and additional variables to use in the URL template expansion.
63
+ *
64
+ * @param string $method HTTP method
65
+ * @param string|UriInterface $uri URI object or string.
66
+ * @param array $options Request options to apply.
67
+ *
68
+ * @return PromiseInterface
69
+ */
70
+ public function requestAsync($method, $uri, array $options = []);
71
+
72
+ /**
73
+ * Get a client configuration option.
74
+ *
75
+ * These options include default request options of the client, a "handler"
76
+ * (if utilized by the concrete client), and a "base_uri" if utilized by
77
+ * the concrete client.
78
+ *
79
+ * @param string|null $option The config option to retrieve.
80
+ *
81
+ * @return mixed
82
+ */
83
+ public function getConfig($option = null);
84
+ }
lib/Azure/GuzzleHttp/Cookie/CookieJar.php ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+ use Psr\Http\Message\ResponseInterface;
6
+
7
+ /**
8
+ * Cookie jar that stores cookies as an array
9
+ */
10
+ class CookieJar implements CookieJarInterface
11
+ {
12
+ /** @var SetCookie[] Loaded cookie data */
13
+ private $cookies = [];
14
+
15
+ /** @var bool */
16
+ private $strictMode;
17
+
18
+ /**
19
+ * @param bool $strictMode Set to true to throw exceptions when invalid
20
+ * cookies are added to the cookie jar.
21
+ * @param array $cookieArray Array of SetCookie objects or a hash of
22
+ * arrays that can be used with the SetCookie
23
+ * constructor
24
+ */
25
+ public function __construct($strictMode = false, $cookieArray = [])
26
+ {
27
+ $this->strictMode = $strictMode;
28
+
29
+ foreach ($cookieArray as $cookie) {
30
+ if (!($cookie instanceof SetCookie)) {
31
+ $cookie = new SetCookie($cookie);
32
+ }
33
+ $this->setCookie($cookie);
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Create a new Cookie jar from an associative array and domain.
39
+ *
40
+ * @param array $cookies Cookies to create the jar from
41
+ * @param string $domain Domain to set the cookies to
42
+ *
43
+ * @return self
44
+ */
45
+ public static function fromArray(array $cookies, $domain)
46
+ {
47
+ $cookieJar = new self();
48
+ foreach ($cookies as $name => $value) {
49
+ $cookieJar->setCookie(new SetCookie([
50
+ 'Domain' => $domain,
51
+ 'Name' => $name,
52
+ 'Value' => $value,
53
+ 'Discard' => true
54
+ ]));
55
+ }
56
+
57
+ return $cookieJar;
58
+ }
59
+
60
+ /**
61
+ * @deprecated
62
+ */
63
+ public static function getCookieValue($value)
64
+ {
65
+ return $value;
66
+ }
67
+
68
+ /**
69
+ * Evaluate if this cookie should be persisted to storage
70
+ * that survives between requests.
71
+ *
72
+ * @param SetCookie $cookie Being evaluated.
73
+ * @param bool $allowSessionCookies If we should persist session cookies
74
+ * @return bool
75
+ */
76
+ public static function shouldPersist(
77
+ SetCookie $cookie,
78
+ $allowSessionCookies = false
79
+ ) {
80
+ if ($cookie->getExpires() || $allowSessionCookies) {
81
+ if (!$cookie->getDiscard()) {
82
+ return true;
83
+ }
84
+ }
85
+
86
+ return false;
87
+ }
88
+
89
+ public function toArray()
90
+ {
91
+ return array_map(function (SetCookie $cookie) {
92
+ return $cookie->toArray();
93
+ }, $this->getIterator()->getArrayCopy());
94
+ }
95
+
96
+ public function clear($domain = null, $path = null, $name = null)
97
+ {
98
+ if (!$domain) {
99
+ $this->cookies = [];
100
+ return;
101
+ } elseif (!$path) {
102
+ $this->cookies = array_filter(
103
+ $this->cookies,
104
+ function (SetCookie $cookie) use ($path, $domain) {
105
+ return !$cookie->matchesDomain($domain);
106
+ }
107
+ );
108
+ } elseif (!$name) {
109
+ $this->cookies = array_filter(
110
+ $this->cookies,
111
+ function (SetCookie $cookie) use ($path, $domain) {
112
+ return !($cookie->matchesPath($path) &&
113
+ $cookie->matchesDomain($domain));
114
+ }
115
+ );
116
+ } else {
117
+ $this->cookies = array_filter(
118
+ $this->cookies,
119
+ function (SetCookie $cookie) use ($path, $domain, $name) {
120
+ return !($cookie->getName() == $name &&
121
+ $cookie->matchesPath($path) &&
122
+ $cookie->matchesDomain($domain));
123
+ }
124
+ );
125
+ }
126
+ }
127
+
128
+ public function clearSessionCookies()
129
+ {
130
+ $this->cookies = array_filter(
131
+ $this->cookies,
132
+ function (SetCookie $cookie) {
133
+ return !$cookie->getDiscard() && $cookie->getExpires();
134
+ }
135
+ );
136
+ }
137
+
138
+ public function setCookie(SetCookie $cookie)
139
+ {
140
+ // If the name string is empty (but not 0), ignore the set-cookie
141
+ // string entirely.
142
+ $name = $cookie->getName();
143
+ if (!$name && $name !== '0') {
144
+ return false;
145
+ }
146
+
147
+ // Only allow cookies with set and valid domain, name, value
148
+ $result = $cookie->validate();
149
+ if ($result !== true) {
150
+ if ($this->strictMode) {
151
+ throw new \RuntimeException('Invalid cookie: ' . $result);
152
+ } else {
153
+ $this->removeCookieIfEmpty($cookie);
154
+ return false;
155
+ }
156
+ }
157
+
158
+ // Resolve conflicts with previously set cookies
159
+ foreach ($this->cookies as $i => $c) {
160
+
161
+ // Two cookies are identical, when their path, and domain are
162
+ // identical.
163
+ if ($c->getPath() != $cookie->getPath() ||
164
+ $c->getDomain() != $cookie->getDomain() ||
165
+ $c->getName() != $cookie->getName()
166
+ ) {
167
+ continue;
168
+ }
169
+
170
+ // The previously set cookie is a discard cookie and this one is
171
+ // not so allow the new cookie to be set
172
+ if (!$cookie->getDiscard() && $c->getDiscard()) {
173
+ unset($this->cookies[$i]);
174
+ continue;
175
+ }
176
+
177
+ // If the new cookie's expiration is further into the future, then
178
+ // replace the old cookie
179
+ if ($cookie->getExpires() > $c->getExpires()) {
180
+ unset($this->cookies[$i]);
181
+ continue;
182
+ }
183
+
184
+ // If the value has changed, we better change it
185
+ if ($cookie->getValue() !== $c->getValue()) {
186
+ unset($this->cookies[$i]);
187
+ continue;
188
+ }
189
+
190
+ // The cookie exists, so no need to continue
191
+ return false;
192
+ }
193
+
194
+ $this->cookies[] = $cookie;
195
+
196
+ return true;
197
+ }
198
+
199
+ public function count()
200
+ {
201
+ return count($this->cookies);
202
+ }
203
+
204
+ public function getIterator()
205
+ {
206
+ return new \ArrayIterator(array_values($this->cookies));
207
+ }
208
+
209
+ public function extractCookies(
210
+ RequestInterface $request,
211
+ ResponseInterface $response
212
+ ) {
213
+ if ($cookieHeader = $response->getHeader('Set-Cookie')) {
214
+ foreach ($cookieHeader as $cookie) {
215
+ $sc = SetCookie::fromString($cookie);
216
+ if (!$sc->getDomain()) {
217
+ $sc->setDomain($request->getUri()->getHost());
218
+ }
219
+ $this->setCookie($sc);
220
+ }
221
+ }
222
+ }
223
+
224
+ public function withCookieHeader(RequestInterface $request)
225
+ {
226
+ $values = [];
227
+ $uri = $request->getUri();
228
+ $scheme = $uri->getScheme();
229
+ $host = $uri->getHost();
230
+ $path = $uri->getPath() ?: '/';
231
+
232
+ foreach ($this->cookies as $cookie) {
233
+ if ($cookie->matchesPath($path) &&
234
+ $cookie->matchesDomain($host) &&
235
+ !$cookie->isExpired() &&
236
+ (!$cookie->getSecure() || $scheme === 'https')
237
+ ) {
238
+ $values[] = $cookie->getName() . '='
239
+ . $cookie->getValue();
240
+ }
241
+ }
242
+
243
+ return $values
244
+ ? $request->withHeader('Cookie', implode('; ', $values))
245
+ : $request;
246
+ }
247
+
248
+ /**
249
+ * If a cookie already exists and the server asks to set it again with a
250
+ * null value, the cookie must be deleted.
251
+ *
252
+ * @param SetCookie $cookie
253
+ */
254
+ private function removeCookieIfEmpty(SetCookie $cookie)
255
+ {
256
+ $cookieValue = $cookie->getValue();
257
+ if ($cookieValue === null || $cookieValue === '') {
258
+ $this->clear(
259
+ $cookie->getDomain(),
260
+ $cookie->getPath(),
261
+ $cookie->getName()
262
+ );
263
+ }
264
+ }
265
+ }
lib/Azure/GuzzleHttp/Cookie/CookieJarInterface.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+ use Psr\Http\Message\ResponseInterface;
6
+
7
+ /**
8
+ * Stores HTTP cookies.
9
+ *
10
+ * It extracts cookies from HTTP requests, and returns them in HTTP responses.
11
+ * CookieJarInterface instances automatically expire contained cookies when
12
+ * necessary. Subclasses are also responsible for storing and retrieving
13
+ * cookies from a file, database, etc.
14
+ *
15
+ * @link http://docs.python.org/2/library/cookielib.html Inspiration
16
+ */
17
+ interface CookieJarInterface extends \Countable, \IteratorAggregate
18
+ {
19
+ /**
20
+ * Create a request with added cookie headers.
21
+ *
22
+ * If no matching cookies are found in the cookie jar, then no Cookie
23
+ * header is added to the request and the same request is returned.
24
+ *
25
+ * @param RequestInterface $request Request object to modify.
26
+ *
27
+ * @return RequestInterface returns the modified request.
28
+ */
29
+ public function withCookieHeader(RequestInterface $request);
30
+
31
+ /**
32
+ * Extract cookies from an HTTP response and store them in the CookieJar.
33
+ *
34
+ * @param RequestInterface $request Request that was sent
35
+ * @param ResponseInterface $response Response that was received
36
+ */
37
+ public function extractCookies(
38
+ RequestInterface $request,
39
+ ResponseInterface $response
40
+ );
41
+
42
+ /**
43
+ * Sets a cookie in the cookie jar.
44
+ *
45
+ * @param SetCookie $cookie Cookie to set.
46
+ *
47
+ * @return bool Returns true on success or false on failure
48
+ */
49
+ public function setCookie(SetCookie $cookie);
50
+
51
+ /**
52
+ * Remove cookies currently held in the cookie jar.
53
+ *
54
+ * Invoking this method without arguments will empty the whole cookie jar.
55
+ * If given a $domain argument only cookies belonging to that domain will
56
+ * be removed. If given a $domain and $path argument, cookies belonging to
57
+ * the specified path within that domain are removed. If given all three
58
+ * arguments, then the cookie with the specified name, path and domain is
59
+ * removed.
60
+ *
61
+ * @param string $domain Clears cookies matching a domain
62
+ * @param string $path Clears cookies matching a domain and path
63
+ * @param string $name Clears cookies matching a domain, path, and name
64
+ *
65
+ * @return CookieJarInterface
66
+ */
67
+ public function clear($domain = null, $path = null, $name = null);
68
+
69
+ /**
70
+ * Discard all sessions cookies.
71
+ *
72
+ * Removes cookies that don't have an expire field or a have a discard
73
+ * field set to true. To be called when the user agent shuts down according
74
+ * to RFC 2965.
75
+ */
76
+ public function clearSessionCookies();
77
+
78
+ /**
79
+ * Converts the cookie jar to an array.
80
+ *
81
+ * @return array
82
+ */
83
+ public function toArray();
84
+ }
lib/Azure/GuzzleHttp/Cookie/FileCookieJar.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ /**
5
+ * Persists non-session cookies using a JSON formatted file
6
+ */
7
+ class FileCookieJar extends CookieJar
8
+ {
9
+ /** @var string filename */
10
+ private $filename;
11
+
12
+ /** @var bool Control whether to persist session cookies or not. */
13
+ private $storeSessionCookies;
14
+
15
+ /**
16
+ * Create a new FileCookieJar object
17
+ *
18
+ * @param string $cookieFile File to store the cookie data
19
+ * @param bool $storeSessionCookies Set to true to store session cookies
20
+ * in the cookie jar.
21
+ *
22
+ * @throws \RuntimeException if the file cannot be found or created
23
+ */
24
+ public function __construct($cookieFile, $storeSessionCookies = false)
25
+ {
26
+ $this->filename = $cookieFile;
27
+ $this->storeSessionCookies = $storeSessionCookies;
28
+
29
+ if (file_exists($cookieFile)) {
30
+ $this->load($cookieFile);
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Saves the file when shutting down
36
+ */
37
+ public function __destruct()
38
+ {
39
+ $this->save($this->filename);
40
+ }
41
+
42
+ /**
43
+ * Saves the cookies to a file.
44
+ *
45
+ * @param string $filename File to save
46
+ * @throws \RuntimeException if the file cannot be found or created
47
+ */
48
+ public function save($filename)
49
+ {
50
+ $json = [];
51
+ foreach ($this as $cookie) {
52
+ /** @var SetCookie $cookie */
53
+ if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
54
+ $json[] = $cookie->toArray();
55
+ }
56
+ }
57
+
58
+ $jsonStr = \GuzzleHttp\json_encode($json);
59
+ if (false === file_put_contents($filename, $jsonStr)) {
60
+ throw new \RuntimeException("Unable to save file {$filename}");
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Load cookies from a JSON formatted file.
66
+ *
67
+ * Old cookies are kept unless overwritten by newly loaded ones.
68
+ *
69
+ * @param string $filename Cookie file to load.
70
+ * @throws \RuntimeException if the file cannot be loaded.
71
+ */
72
+ public function load($filename)
73
+ {
74
+ $json = file_get_contents($filename);
75
+ if (false === $json) {
76
+ throw new \RuntimeException("Unable to load file {$filename}");
77
+ } elseif ($json === '') {
78
+ return;
79
+ }
80
+
81
+ $data = \GuzzleHttp\json_decode($json, true);
82
+ if (is_array($data)) {
83
+ foreach (json_decode($json, true) as $cookie) {
84
+ $this->setCookie(new SetCookie($cookie));
85
+ }
86
+ } elseif (strlen($data)) {
87
+ throw new \RuntimeException("Invalid cookie file: {$filename}");
88
+ }
89
+ }
90
+ }
lib/Azure/GuzzleHttp/Cookie/SessionCookieJar.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ /**
5
+ * Persists cookies in the client session
6
+ */
7
+ class SessionCookieJar extends CookieJar
8
+ {
9
+ /** @var string session key */
10
+ private $sessionKey;
11
+
12
+ /** @var bool Control whether to persist session cookies or not. */
13
+ private $storeSessionCookies;
14
+
15
+ /**
16
+ * Create a new SessionCookieJar object
17
+ *
18
+ * @param string $sessionKey Session key name to store the cookie
19
+ * data in session
20
+ * @param bool $storeSessionCookies Set to true to store session cookies
21
+ * in the cookie jar.
22
+ */
23
+ public function __construct($sessionKey, $storeSessionCookies = false)
24
+ {
25
+ $this->sessionKey = $sessionKey;
26
+ $this->storeSessionCookies = $storeSessionCookies;
27
+ $this->load();
28
+ }
29
+
30
+ /**
31
+ * Saves cookies to session when shutting down
32
+ */
33
+ public function __destruct()
34
+ {
35
+ $this->save();
36
+ }
37
+
38
+ /**
39
+ * Save cookies to the client session
40
+ */
41
+ public function save()
42
+ {
43
+ $json = [];
44
+ foreach ($this as $cookie) {
45
+ /** @var SetCookie $cookie */
46
+ if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
47
+ $json[] = $cookie->toArray();
48
+ }
49
+ }
50
+
51
+ $_SESSION[$this->sessionKey] = json_encode($json);
52
+ }
53
+
54
+ /**
55
+ * Load the contents of the client session into the data array
56
+ */
57
+ protected function load()
58
+ {
59
+ if (!isset($_SESSION[$this->sessionKey])) {
60
+ return;
61
+ }
62
+ $data = json_decode($_SESSION[$this->sessionKey], true);
63
+ if (is_array($data)) {
64
+ foreach ($data as $cookie) {
65
+ $this->setCookie(new SetCookie($cookie));
66
+ }
67
+ } elseif (strlen($data)) {
68
+ throw new \RuntimeException("Invalid cookie data");
69
+ }
70
+ }
71
+ }
lib/Azure/GuzzleHttp/Cookie/SetCookie.php ADDED
@@ -0,0 +1,404 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ /**
5
+ * Set-Cookie object
6
+ */
7
+ class SetCookie
8
+ {
9
+ /** @var array */
10
+ private static $defaults = [
11
+ 'Name' => null,
12
+ 'Value' => null,
13
+ 'Domain' => null,
14
+ 'Path' => '/',
15
+ 'Max-Age' => null,
16
+ 'Expires' => null,
17
+ 'Secure' => false,
18
+ 'Discard' => false,
19
+ 'HttpOnly' => false
20
+ ];
21
+
22
+ /** @var array Cookie data */
23
+ private $data;
24
+
25
+ /**
26
+ * Create a new SetCookie object from a string
27
+ *
28
+ * @param string $cookie Set-Cookie header string
29
+ *
30
+ * @return self
31
+ */
32
+ public static function fromString($cookie)
33
+ {
34
+ // Create the default return array
35
+ $data = self::$defaults;
36
+ // Explode the cookie string using a series of semicolons
37
+ $pieces = array_filter(array_map('trim', explode(';', $cookie)));
38
+ // The name of the cookie (first kvp) must include an equal sign.
39
+ if (empty($pieces) || !strpos($pieces[0], '=')) {
40
+ return new self($data);
41
+ }
42
+
43
+ // Add the cookie pieces into the parsed data array
44
+ foreach ($pieces as $part) {
45
+
46
+ $cookieParts = explode('=', $part, 2);
47
+ $key = trim($cookieParts[0]);
48
+ $value = isset($cookieParts[1])
49
+ ? trim($cookieParts[1], " \n\r\t\0\x0B")
50
+ : true;
51
+
52
+ // Only check for non-cookies when cookies have been found
53
+ if (empty($data['Name'])) {
54
+ $data['Name'] = $key;
55
+ $data['Value'] = $value;
56
+ } else {
57
+ foreach (array_keys(self::$defaults) as $search) {
58
+ if (!strcasecmp($search, $key)) {
59
+ $data[$search] = $value;
60
+ continue 2;
61
+ }
62
+ }
63
+ $data[$key] = $value;
64
+ }
65
+ }
66
+
67
+ return new self($data);
68
+ }
69
+
70
+ /**
71
+ * @param array $data Array of cookie data provided by a Cookie parser
72
+ */
73
+ public function __construct(array $data = [])
74
+ {
75
+ $this->data = array_replace(self::$defaults, $data);
76
+ // Extract the Expires value and turn it into a UNIX timestamp if needed
77
+ if (!$this->getExpires() && $this->getMaxAge()) {
78
+ // Calculate the Expires date
79
+ $this->setExpires(time() + $this->getMaxAge());
80
+ } elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
81
+ $this->setExpires($this->getExpires());
82
+ }
83
+ }
84
+
85
+ public function __toString()
86
+ {
87
+ $str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
88
+ foreach ($this->data as $k => $v) {
89
+ if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) {
90
+ if ($k === 'Expires') {
91
+ $str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
92
+ } else {
93
+ $str .= ($v === true ? $k : "{$k}={$v}") . '; ';
94
+ }
95
+ }
96
+ }
97
+
98
+ return rtrim($str, '; ');
99
+ }
100
+
101
+ public function toArray()
102
+ {
103
+ return $this->data;
104
+ }
105
+
106
+ /**
107
+ * Get the cookie name
108
+ *
109
+ * @return string
110
+ */
111
+ public function getName()
112
+ {
113
+ return $this->data['Name'];
114
+ }
115
+
116
+ /**
117
+ * Set the cookie name
118
+ *
119
+ * @param string $name Cookie name
120
+ */
121
+ public function setName($name)
122
+ {
123
+ $this->data['Name'] = $name;
124
+ }
125
+
126
+ /**
127
+ * Get the cookie value
128
+ *
129
+ * @return string
130
+ */
131
+ public function getValue()
132
+ {
133
+ return $this->data['Value'];
134
+ }
135
+
136
+ /**
137
+ * Set the cookie value
138
+ *
139
+ * @param string $value Cookie value
140
+ */
141
+ public function setValue($value)
142
+ {
143
+ $this->data['Value'] = $value;
144
+ }
145
+
146
+ /**
147
+ * Get the domain
148
+ *
149
+ * @return string|null
150
+ */
151
+ public function getDomain()
152
+ {
153
+ return $this->data['Domain'];
154
+ }
155
+
156
+ /**
157
+ * Set the domain of the cookie
158
+ *
159
+ * @param string $domain
160
+ */
161
+ public function setDomain($domain)
162
+ {
163
+ $this->data['Domain'] = $domain;
164
+ }
165
+
166
+ /**
167
+ * Get the path
168
+ *
169
+ * @return string
170
+ */
171
+ public function getPath()
172
+ {
173
+ return $this->data['Path'];
174
+ }
175
+
176
+ /**
177
+ * Set the path of the cookie
178
+ *
179
+ * @param string $path Path of the cookie
180
+ */
181
+ public function setPath($path)
182
+ {
183
+ $this->data['Path'] = $path;
184
+ }
185
+
186
+ /**
187
+ * Maximum lifetime of the cookie in seconds
188
+ *
189
+ * @return int|null
190
+ */
191
+ public function getMaxAge()
192
+ {
193
+ return $this->data['Max-Age'];
194
+ }
195
+
196
+ /**
197
+ * Set the max-age of the cookie
198
+ *
199
+ * @param int $maxAge Max age of the cookie in seconds
200
+ */
201
+ public function setMaxAge($maxAge)
202
+ {
203
+ $this->data['Max-Age'] = $maxAge;
204
+ }
205
+
206
+ /**
207
+ * The UNIX timestamp when the cookie Expires
208
+ *
209
+ * @return mixed
210
+ */
211
+ public function getExpires()
212
+ {
213
+ return $this->data['Expires'];
214
+ }
215
+
216
+ /**
217
+ * Set the unix timestamp for which the cookie will expire
218
+ *
219
+ * @param int $timestamp Unix timestamp
220
+ */
221
+ public function setExpires($timestamp)
222
+ {
223
+ $this->data['Expires'] = is_numeric($timestamp)
224
+ ? (int) $timestamp
225
+ : strtotime($timestamp);
226
+ }
227
+
228
+ /**
229
+ * Get whether or not this is a secure cookie
230
+ *
231
+ * @return null|bool
232
+ */
233
+ public function getSecure()
234
+ {
235
+ return $this->data['Secure'];
236
+ }
237
+
238
+ /**
239
+ * Set whether or not the cookie is secure
240
+ *
241
+ * @param bool $secure Set to true or false if secure
242
+ */
243
+ public function setSecure($secure)
244
+ {
245
+ $this->data['Secure'] = $secure;
246
+ }
247
+
248
+ /**
249
+ * Get whether or not this is a session cookie
250
+ *
251
+ * @return null|bool
252
+ */
253
+ public function getDiscard()
254
+ {
255
+ return $this->data['Discard'];
256
+ }
257
+
258
+ /**
259
+ * Set whether or not this is a session cookie
260
+ *
261
+ * @param bool $discard Set to true or false if this is a session cookie
262
+ */
263
+ public function setDiscard($discard)
264
+ {
265
+ $this->data['Discard'] = $discard;
266
+ }
267
+
268
+ /**
269
+ * Get whether or not this is an HTTP only cookie
270
+ *
271
+ * @return bool
272
+ */
273
+ public function getHttpOnly()
274
+ {
275
+ return $this->data['HttpOnly'];
276
+ }
277
+
278
+ /**
279
+ * Set whether or not this is an HTTP only cookie
280
+ *
281
+ * @param bool $httpOnly Set to true or false if this is HTTP only
282
+ */
283
+ public function setHttpOnly($httpOnly)
284
+ {
285
+ $this->data['HttpOnly'] = $httpOnly;
286
+ }
287
+
288
+ /**
289
+ * Check if the cookie matches a path value.
290
+ *
291
+ * A request-path path-matches a given cookie-path if at least one of
292
+ * the following conditions holds:
293
+ *
294
+ * - The cookie-path and the request-path are identical.
295
+ * - The cookie-path is a prefix of the request-path, and the last
296
+ * character of the cookie-path is %x2F ("/").
297
+ * - The cookie-path is a prefix of the request-path, and the first
298
+ * character of the request-path that is not included in the cookie-
299
+ * path is a %x2F ("/") character.
300
+ *
301
+ * @param string $requestPath Path to check against
302
+ *
303
+ * @return bool
304
+ */
305
+ public function matchesPath($requestPath)
306
+ {
307
+ $cookiePath = $this->getPath();
308
+
309
+ // Match on exact matches or when path is the default empty "/"
310
+ if ($cookiePath === '/' || $cookiePath == $requestPath) {
311
+ return true;
312
+ }
313
+
314
+ // Ensure that the cookie-path is a prefix of the request path.
315
+ if (0 !== strpos($requestPath, $cookiePath)) {
316
+ return false;
317
+ }
318
+
319
+ // Match if the last character of the cookie-path is "/"
320
+ if (substr($cookiePath, -1, 1) === '/') {
321
+ return true;
322
+ }
323
+
324
+ // Match if the first character not included in cookie path is "/"
325
+ return substr($requestPath, strlen($cookiePath), 1) === '/';
326
+ }
327
+
328
+ /**
329
+ * Check if the cookie matches a domain value
330
+ *
331
+ * @param string $domain Domain to check against
332
+ *
333
+ * @return bool
334
+ */
335
+ public function matchesDomain($domain)
336
+ {
337
+ // Remove the leading '.' as per spec in RFC 6265.
338
+ // http://tools.ietf.org/html/rfc6265#section-5.2.3
339
+ $cookieDomain = ltrim($this->getDomain(), '.');
340
+
341
+ // Domain not set or exact match.
342
+ if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
343
+ return true;
344
+ }
345
+
346
+ // Matching the subdomain according to RFC 6265.
347
+ // http://tools.ietf.org/html/rfc6265#section-5.1.3
348
+ if (filter_var($domain, FILTER_VALIDATE_IP)) {
349
+ return false;
350
+ }
351
+
352
+ return (bool) preg_match('/\.' . preg_quote($cookieDomain) . '$/', $domain);
353
+ }
354
+
355
+ /**
356
+ * Check if the cookie is expired
357
+ *
358
+ * @return bool
359
+ */
360
+ public function isExpired()
361
+ {
362
+ return $this->getExpires() && time() > $this->getExpires();
363
+ }
364
+
365
+ /**
366
+ * Check if the cookie is valid according to RFC 6265
367
+ *
368
+ * @return bool|string Returns true if valid or an error message if invalid
369
+ */
370
+ public function validate()
371
+ {
372
+ // Names must not be empty, but can be 0
373
+ $name = $this->getName();
374
+ if (empty($name) && !is_numeric($name)) {
375
+ return 'The cookie name must not be empty';
376
+ }
377
+
378
+ // Check if any of the invalid characters are present in the cookie name
379
+ if (preg_match(
380
+ '/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/',
381
+ $name)
382
+ ) {
383
+ return 'Cookie name must not contain invalid characters: ASCII '
384
+ . 'Control characters (0-31;127), space, tab and the '
385
+ . 'following characters: ()<>@,;:\"/?={}';
386
+ }
387
+
388
+ // Value must not be empty, but can be 0
389
+ $value = $this->getValue();
390
+ if (empty($value) && !is_numeric($value)) {
391
+ return 'The cookie value must not be empty';
392
+ }
393
+
394
+ // Domains must not be empty, but can be 0
395
+ // A "0" is not a valid internet domain, but may be used as server name
396
+ // in a private network.
397
+ $domain = $this->getDomain();
398
+ if (empty($domain) && !is_numeric($domain)) {
399
+ return 'The cookie domain must not be empty';
400
+ }
401
+
402
+ return true;
403
+ }
404
+ }
lib/Azure/GuzzleHttp/Exception/BadResponseException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ /**
5
+ * Exception when an HTTP error occurs (4xx or 5xx error)
6
+ */
7
+ class BadResponseException extends RequestException {}
lib/Azure/GuzzleHttp/Exception/ClientException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ /**
5
+ * Exception when a client error is encountered (4xx codes)
6
+ */
7
+ class ClientException extends BadResponseException {}
lib/Azure/GuzzleHttp/Exception/ConnectException.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+
6
+ /**
7
+ * Exception thrown when a connection cannot be established.
8
+ *
9
+ * Note that no response is present for a ConnectException
10
+ */
11
+ class ConnectException extends RequestException
12
+ {
13
+ public function __construct(
14
+ $message,
15
+ RequestInterface $request,
16
+ \Exception $previous = null,
17
+ array $handlerContext = []
18
+ ) {
19
+ parent::__construct($message, $request, null, $previous, $handlerContext);
20
+ }
21
+
22
+ /**
23
+ * @return null
24
+ */
25
+ public function getResponse()
26
+ {
27
+ return null;
28
+ }
29
+
30
+ /**
31
+ * @return bool
32
+ */
33
+ public function hasResponse()
34
+ {
35
+ return false;
36
+ }
37
+ }
lib/Azure/GuzzleHttp/Exception/GuzzleException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ interface GuzzleException {}
lib/Azure/GuzzleHttp/Exception/RequestException.php ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+ use Psr\Http\Message\ResponseInterface;
6
+ use GuzzleHttp\Promise\PromiseInterface;
7
+ use Psr\Http\Message\UriInterface;
8
+
9
+ /**
10
+ * HTTP Request exception
11
+ */
12
+ class RequestException extends TransferException
13
+ {
14
+ /** @var RequestInterface */
15
+ private $request;
16
+
17
+ /** @var ResponseInterface */
18
+ private $response;
19
+
20
+ /** @var array */
21
+ private $handlerContext;
22
+
23
+ public function __construct(
24
+ $message,
25
+ RequestInterface $request,
26
+ ResponseInterface $response = null,
27
+ \Exception $previous = null,
28
+ array $handlerContext = []
29
+ ) {
30
+ // Set the code of the exception if the response is set and not future.
31
+ $code = $response && !($response instanceof PromiseInterface)
32
+ ? $response->getStatusCode()
33
+ : 0;
34
+ parent::__construct($message, $code, $previous);
35
+ $this->request = $request;
36
+ $this->response = $response;
37
+ $this->handlerContext = $handlerContext;
38
+ }
39
+
40
+ /**
41
+ * Wrap non-RequestExceptions with a RequestException
42
+ *
43
+ * @param RequestInterface $request
44
+ * @param \Exception $e
45
+ *
46
+ * @return RequestException
47
+ */
48
+ public static function wrapException(RequestInterface $request, \Exception $e)
49
+ {
50
+ return $e instanceof RequestException
51
+ ? $e
52
+ : new RequestException($e->getMessage(), $request, null, $e);
53
+ }
54
+
55
+ /**
56
+ * Factory method to create a new exception with a normalized error message
57
+ *
58
+ * @param RequestInterface $request Request
59
+ * @param ResponseInterface $response Response received
60
+ * @param \Exception $previous Previous exception
61
+ * @param array $ctx Optional handler context.
62
+ *
63
+ * @return self
64
+ */
65
+ public static function create(
66
+ RequestInterface $request,
67
+ ResponseInterface $response = null,
68
+ \Exception $previous = null,
69
+ array $ctx = []
70
+ ) {
71
+ if (!$response) {
72
+ return new self(
73
+ 'Error completing request',
74
+ $request,
75
+ null,
76
+ $previous,
77
+ $ctx
78
+ );
79
+ }
80
+
81
+ $level = (int) floor($response->getStatusCode() / 100);
82
+ if ($level === 4) {
83
+ $label = 'Client error';
84
+ $className = __NAMESPACE__ . '\\ClientException';
85
+ } elseif ($level === 5) {
86
+ $label = 'Server error';
87
+ $className = __NAMESPACE__ . '\\ServerException';
88
+ } else {
89
+ $label = 'Unsuccessful request';
90
+ $className = __CLASS__;
91
+ }
92
+
93
+ $uri = $request->getUri();
94
+ $uri = static::obfuscateUri($uri);
95
+
96
+ // Server Error: `GET /` resulted in a `404 Not Found` response:
97
+ // <html> ... (truncated)
98
+ $message = sprintf(
99
+ '%s: `%s` resulted in a `%s` response',
100
+ $label,
101
+ $request->getMethod() . ' ' . $uri,
102
+ $response->getStatusCode() . ' ' . $response->getReasonPhrase()
103
+ );
104
+
105
+ $summary = static::getResponseBodySummary($response);
106
+
107
+ if ($summary !== null) {
108
+ $message .= ":\n{$summary}\n";
109
+ }
110
+
111
+ return new $className($message, $request, $response, $previous, $ctx);
112
+ }
113
+
114
+ /**
115
+ * Get a short summary of the response
116
+ *
117
+ * Will return `null` if the response is not printable.
118
+ *
119
+ * @param ResponseInterface $response
120
+ *
121
+ * @return string|null
122
+ */
123
+ public static function getResponseBodySummary(ResponseInterface $response)
124
+ {
125
+ $body = $response->getBody();
126
+
127
+ if (!$body->isSeekable()) {
128
+ return null;
129
+ }
130
+
131
+ $size = $body->getSize();
132
+ $summary = $body->read(120);
133
+ $body->rewind();
134
+
135
+ if ($size > 120) {
136
+ $summary .= ' (truncated...)';
137
+ }
138
+
139
+ // Matches any printable character, including unicode characters:
140
+ // letters, marks, numbers, punctuation, spacing, and separators.
141
+ if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) {
142
+ return null;
143
+ }
144
+
145
+ return $summary;
146
+ }
147
+
148
+ /**
149
+ * Obfuscates URI if there is an username and a password present
150
+ *
151
+ * @param UriInterface $uri
152
+ *
153
+ * @return UriInterface
154
+ */
155
+ private static function obfuscateUri($uri)
156
+ {
157
+ $userInfo = $uri->getUserInfo();
158
+
159
+ if (false !== ($pos = strpos($userInfo, ':'))) {
160
+ return $uri->withUserInfo(substr($userInfo, 0, $pos), '***');
161
+ }
162
+
163
+ return $uri;
164
+ }
165
+
166
+ /**
167
+ * Get the request that caused the exception
168
+ *
169
+ * @return RequestInterface
170
+ */
171
+ public function getRequest()
172
+ {
173
+ return $this->request;
174
+ }
175
+
176
+ /**
177
+ * Get the associated response
178
+ *
179
+ * @return ResponseInterface|null
180
+ */
181
+ public function getResponse()
182
+ {
183
+ return $this->response;
184
+ }
185
+
186
+ /**
187
+ * Check if a response was received
188
+ *
189
+ * @return bool
190
+ */
191
+ public function hasResponse()
192
+ {
193
+ return $this->response !== null;
194
+ }
195
+
196
+ /**
197
+ * Get contextual information about the error from the underlying handler.
198
+ *
199
+ * The contents of this array will vary depending on which handler you are
200
+ * using. It may also be just an empty array. Relying on this data will
201
+ * couple you to a specific handler, but can give more debug information
202
+ * when needed.
203
+ *
204
+ * @return array
205
+ */
206
+ public function getHandlerContext()
207
+ {
208
+ return $this->handlerContext;
209
+ }
210
+ }
lib/Azure/GuzzleHttp/Exception/SeekException.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Exception thrown when a seek fails on a stream.
8
+ */
9
+ class SeekException extends \RuntimeException implements GuzzleException
10
+ {
11
+ private $stream;
12
+
13
+ public function __construct(StreamInterface $stream, $pos = 0, $msg = '')
14
+ {
15
+ $this->stream = $stream;
16
+ $msg = $msg ?: 'Could not seek the stream to position ' . $pos;
17
+ parent::__construct($msg);
18
+ }
19
+
20
+ /**
21
+ * @return StreamInterface
22
+ */
23
+ public function getStream()
24
+ {
25
+ return $this->stream;
26
+ }
27
+ }
lib/Azure/GuzzleHttp/Exception/ServerException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ /**
5
+ * Exception when a server error is encountered (5xx codes)
6
+ */
7
+ class ServerException extends BadResponseException {}
lib/Azure/GuzzleHttp/Exception/TooManyRedirectsException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class TooManyRedirectsException extends RequestException {}
lib/Azure/GuzzleHttp/Exception/TransferException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class TransferException extends \RuntimeException implements GuzzleException {}
lib/Azure/GuzzleHttp/Handler/CurlFactory.php ADDED
@@ -0,0 +1,536 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Exception\RequestException;
5
+ use GuzzleHttp\Exception\ConnectException;
6
+ use GuzzleHttp\Promise\FulfilledPromise;
7
+ use GuzzleHttp\Promise\RejectedPromise;
8
+ use GuzzleHttp\Psr7;
9
+ use GuzzleHttp\Psr7\LazyOpenStream;
10
+ use GuzzleHttp\TransferStats;
11
+ use Psr\Http\Message\RequestInterface;
12
+
13
+ /**
14
+ * Creates curl resources from a request
15
+ */
16
+ class CurlFactory implements CurlFactoryInterface
17
+ {
18
+ /** @var array */
19
+ private $handles;
20
+
21
+ /** @var int Total number of idle handles to keep in cache */
22
+ private $maxHandles;
23
+
24
+ /**
25
+ * @param int $maxHandles Maximum number of idle handles.
26
+ */
27
+ public function __construct($maxHandles)
28
+ {
29
+ $this->maxHandles = $maxHandles;
30
+ }
31
+
32
+ public function create(RequestInterface $request, array $options)
33
+ {
34
+ if (isset($options['curl']['body_as_string'])) {
35
+ $options['_body_as_string'] = $options['curl']['body_as_string'];
36
+ unset($options['curl']['body_as_string']);
37
+ }
38
+
39
+ $easy = new EasyHandle;
40
+ $easy->request = $request;
41
+ $easy->options = $options;
42
+ $conf = $this->getDefaultConf($easy);
43
+ $this->applyMethod($easy, $conf);
44
+ $this->applyHandlerOptions($easy, $conf);
45
+ $this->applyHeaders($easy, $conf);
46
+ unset($conf['_headers']);
47
+
48
+ // Add handler options from the request configuration options
49
+ if (isset($options['curl'])) {
50
+ $conf = array_replace($conf, $options['curl']);
51
+ }
52
+
53
+ $conf[CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);
54
+ $easy->handle = $this->handles
55
+ ? array_pop($this->handles)
56
+ : curl_init();
57
+ curl_setopt_array($easy->handle, $conf);
58
+
59
+ return $easy;
60
+ }
61
+
62
+ public function release(EasyHandle $easy)
63
+ {
64
+ $resource = $easy->handle;
65
+ unset($easy->handle);
66
+
67
+ if (count($this->handles) >= $this->maxHandles) {
68
+ curl_close($resource);
69
+ } else {
70
+ // Remove all callback functions as they can hold onto references
71
+ // and are not cleaned up by curl_reset. Using curl_setopt_array
72
+ // does not work for some reason, so removing each one
73
+ // individually.
74
+ curl_setopt($resource, CURLOPT_HEADERFUNCTION, null);
75
+ curl_setopt($resource, CURLOPT_READFUNCTION, null);
76
+ curl_setopt($resource, CURLOPT_WRITEFUNCTION, null);
77
+ curl_setopt($resource, CURLOPT_PROGRESSFUNCTION, null);
78
+ curl_reset($resource);
79
+ $this->handles[] = $resource;
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Completes a cURL transaction, either returning a response promise or a
85
+ * rejected promise.
86
+ *
87
+ * @param callable $handler
88
+ * @param EasyHandle $easy
89
+ * @param CurlFactoryInterface $factory Dictates how the handle is released
90
+ *
91
+ * @return \GuzzleHttp\Promise\PromiseInterface
92
+ */
93
+ public static function finish(
94
+ callable $handler,
95
+ EasyHandle $easy,
96
+ CurlFactoryInterface $factory
97
+ ) {
98
+ if (isset($easy->options['on_stats'])) {
99
+ self::invokeStats($easy);
100
+ }
101
+
102
+ if (!$easy->response || $easy->errno) {
103
+ return self::finishError($handler, $easy, $factory);
104
+ }
105
+
106
+ // Return the response if it is present and there is no error.
107
+ $factory->release($easy);
108
+
109
+ // Rewind the body of the response if possible.
110
+ $body = $easy->response->getBody();
111
+ if ($body->isSeekable()) {
112
+ $body->rewind();
113
+ }
114
+
115
+ return new FulfilledPromise($easy->response);
116
+ }
117
+
118
+ private static function invokeStats(EasyHandle $easy)
119
+ {
120
+ $curlStats = curl_getinfo($easy->handle);
121
+ $stats = new TransferStats(
122
+ $easy->request,
123
+ $easy->response,
124
+ $curlStats['total_time'],
125
+ $easy->errno,
126
+ $curlStats
127
+ );
128
+ call_user_func($easy->options['on_stats'], $stats);
129
+ }
130
+
131
+ private static function finishError(
132
+ callable $handler,
133
+ EasyHandle $easy,
134
+ CurlFactoryInterface $factory
135
+ ) {
136
+ // Get error information and release the handle to the factory.
137
+ $ctx = [
138
+ 'errno' => $easy->errno,
139
+ 'error' => curl_error($easy->handle),
140
+ ] + curl_getinfo($easy->handle);
141
+ $factory->release($easy);
142
+
143
+ // Retry when nothing is present or when curl failed to rewind.
144
+ if (empty($easy->options['_err_message'])
145
+ && (!$easy->errno || $easy->errno == 65)
146
+ ) {
147
+ return self::retryFailedRewind($handler, $easy, $ctx);
148
+ }
149
+
150
+ return self::createRejection($easy, $ctx);
151
+ }
152
+
153
+ private static function createRejection(EasyHandle $easy, array $ctx)
154
+ {
155
+ static $connectionErrors = [
156
+ CURLE_OPERATION_TIMEOUTED => true,
157
+ CURLE_COULDNT_RESOLVE_HOST => true,
158
+ CURLE_COULDNT_CONNECT => true,
159
+ CURLE_SSL_CONNECT_ERROR => true,
160
+ CURLE_GOT_NOTHING => true,
161
+ ];
162
+
163
+ // If an exception was encountered during the onHeaders event, then
164
+ // return a rejected promise that wraps that exception.
165
+ if ($easy->onHeadersException) {
166
+ return new RejectedPromise(
167
+ new RequestException(
168
+ 'An error was encountered during the on_headers event',
169
+ $easy->request,
170
+ $easy->response,
171
+ $easy->onHeadersException,
172
+ $ctx
173
+ )
174
+ );
175
+ }
176
+
177
+ $message = sprintf(
178
+ 'cURL error %s: %s (%s)',
179
+ $ctx['errno'],
180
+ $ctx['error'],
181
+ 'see http://curl.haxx.se/libcurl/c/libcurl-errors.html'
182
+ );
183
+
184
+ // Create a connection exception if it was a specific error code.
185
+ $error = isset($connectionErrors[$easy->errno])
186
+ ? new ConnectException($message, $easy->request, null, $ctx)
187
+ : new RequestException($message, $easy->request, $easy->response, null, $ctx);
188
+
189
+ return new RejectedPromise($error);
190
+ }
191
+
192
+ private function getDefaultConf(EasyHandle $easy)
193
+ {
194
+ $conf = [
195
+ '_headers' => $easy->request->getHeaders(),
196
+ CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(),
197
+ CURLOPT_URL => (string) $easy->request->getUri()->withFragment(''),
198
+ CURLOPT_RETURNTRANSFER => false,
199
+ CURLOPT_HEADER => false,
200
+ CURLOPT_CONNECTTIMEOUT => 150,
201
+ ];
202
+
203
+ if (defined('CURLOPT_PROTOCOLS')) {
204
+ $conf[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
205
+ }
206
+
207
+ $version = $easy->request->getProtocolVersion();
208
+ if ($version == 1.1) {
209
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
210
+ } elseif ($version == 2.0) {
211
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0;
212
+ } else {
213
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
214
+ }
215
+
216
+ return $conf;
217
+ }
218
+
219
+ private function applyMethod(EasyHandle $easy, array &$conf)
220
+ {
221
+ $body = $easy->request->getBody();
222
+ $size = $body->getSize();
223
+
224
+ if ($size === null || $size > 0) {
225
+ $this->applyBody($easy->request, $easy->options, $conf);
226
+ return;
227
+ }
228
+
229
+ $method = $easy->request->getMethod();
230
+ if ($method === 'PUT' || $method === 'POST') {
231
+ // See http://tools.ietf.org/html/rfc7230#section-3.3.2
232
+ if (!$easy->request->hasHeader('Content-Length')) {
233
+ $conf[CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
234
+ }
235
+ } elseif ($method === 'HEAD') {
236
+ $conf[CURLOPT_NOBODY] = true;
237
+ unset(
238
+ $conf[CURLOPT_WRITEFUNCTION],
239
+ $conf[CURLOPT_READFUNCTION],
240
+ $conf[CURLOPT_FILE],
241
+ $conf[CURLOPT_INFILE]
242
+ );
243
+ }
244
+ }
245
+
246
+ private function applyBody(RequestInterface $request, array $options, array &$conf)
247
+ {
248
+ $size = $request->hasHeader('Content-Length')
249
+ ? (int) $request->getHeaderLine('Content-Length')
250
+ : null;
251
+
252
+ // Send the body as a string if the size is less than 1MB OR if the
253
+ // [curl][body_as_string] request value is set.
254
+ if (($size !== null && $size < 1000000) ||
255
+ !empty($options['_body_as_string'])
256
+ ) {
257
+ $conf[CURLOPT_POSTFIELDS] = (string) $request->getBody();
258
+ // Don't duplicate the Content-Length header
259
+ $this->removeHeader('Content-Length', $conf);
260
+ $this->removeHeader('Transfer-Encoding', $conf);
261
+ } else {
262
+ $conf[CURLOPT_UPLOAD] = true;
263
+ if ($size !== null) {
264
+ $conf[CURLOPT_INFILESIZE] = $size;
265
+ $this->removeHeader('Content-Length', $conf);
266
+ }
267
+ $body = $request->getBody();
268
+ if ($body->isSeekable()) {
269
+ $body->rewind();
270
+ }
271
+ $conf[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
272
+ return $body->read($length);
273
+ };
274
+ }
275
+
276
+ // If the Expect header is not present, prevent curl from adding it
277
+ if (!$request->hasHeader('Expect')) {
278
+ $conf[CURLOPT_HTTPHEADER][] = 'Expect:';
279
+ }
280
+
281
+ // cURL sometimes adds a content-type by default. Prevent this.
282
+ if (!$request->hasHeader('Content-Type')) {
283
+ $conf[CURLOPT_HTTPHEADER][] = 'Content-Type:';
284
+ }
285
+ }
286
+
287
+ private function applyHeaders(EasyHandle $easy, array &$conf)
288
+ {
289
+ foreach ($conf['_headers'] as $name => $values) {
290
+ foreach ($values as $value) {
291
+ $conf[CURLOPT_HTTPHEADER][] = "$name: $value";
292
+ }
293
+ }
294
+
295
+ // Remove the Accept header if one was not set
296
+ if (!$easy->request->hasHeader('Accept')) {
297
+ $conf[CURLOPT_HTTPHEADER][] = 'Accept:';
298
+ }
299
+ }
300
+
301
+ /**
302
+ * Remove a header from the options array.
303
+ *
304
+ * @param string $name Case-insensitive header to remove
305
+ * @param array $options Array of options to modify
306
+ */
307
+ private function removeHeader($name, array &$options)
308
+ {
309
+ foreach (array_keys($options['_headers']) as $key) {
310
+ if (!strcasecmp($key, $name)) {
311
+ unset($options['_headers'][$key]);
312
+ return;
313
+ }
314
+ }
315
+ }
316
+
317
+ private function applyHandlerOptions(EasyHandle $easy, array &$conf)
318
+ {
319
+ $options = $easy->options;
320
+ if (isset($options['verify'])) {
321
+ if ($options['verify'] === false) {
322
+ unset($conf[CURLOPT_CAINFO]);
323
+ $conf[CURLOPT_SSL_VERIFYHOST] = 0;
324
+ $conf[CURLOPT_SSL_VERIFYPEER] = false;
325
+ } else {
326
+ $conf[CURLOPT_SSL_VERIFYHOST] = 2;
327
+ $conf[CURLOPT_SSL_VERIFYPEER] = true;
328
+ if (is_string($options['verify'])) {
329
+ $conf[CURLOPT_CAINFO] = $options['verify'];
330
+ if (!file_exists($options['verify'])) {
331
+ throw new \InvalidArgumentException(
332
+ "SSL CA bundle not found: {$options['verify']}"
333
+ );
334
+ }
335
+ }
336
+ }
337
+ }
338
+
339
+ if (!empty($options['decode_content'])) {
340
+ $accept = $easy->request->getHeaderLine('Accept-Encoding');
341
+ if ($accept) {
342
+ $conf[CURLOPT_ENCODING] = $accept;
343
+ } else {
344
+ $conf[CURLOPT_ENCODING] = '';
345
+ // Don't let curl send the header over the wire
346
+ $conf[CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
347
+ }
348
+ }
349
+
350
+ if (isset($options['sink'])) {
351
+ $sink = $options['sink'];
352
+ if (!is_string($sink)) {
353
+ $sink = \GuzzleHttp\Psr7\stream_for($sink);
354
+ } elseif (!is_dir(dirname($sink))) {
355
+ // Ensure that the directory exists before failing in curl.
356
+ throw new \RuntimeException(sprintf(
357
+ 'Directory %s does not exist for sink value of %s',
358
+ dirname($sink),
359
+ $sink
360
+ ));
361
+ } else {
362
+ $sink = new LazyOpenStream($sink, 'w+');
363
+ }
364
+ $easy->sink = $sink;
365
+ $conf[CURLOPT_WRITEFUNCTION] = function ($ch, $write) use ($sink) {
366
+ return $sink->write($write);
367
+ };
368
+ } else {
369
+ // Use a default temp stream if no sink was set.
370
+ $conf[CURLOPT_FILE] = fopen('php://temp', 'w+');
371
+ $easy->sink = Psr7\stream_for($conf[CURLOPT_FILE]);
372
+ }
373
+
374
+ if (isset($options['timeout'])) {
375
+ $conf[CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;
376
+ }
377
+
378
+ if (isset($options['connect_timeout'])) {
379
+ $conf[CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
380
+ }
381
+
382
+ if (isset($options['proxy'])) {
383
+ if (!is_array($options['proxy'])) {
384
+ $conf[CURLOPT_PROXY] = $options['proxy'];
385
+ } else {
386
+ $scheme = $easy->request->getUri()->getScheme();
387
+ if (isset($options['proxy'][$scheme])) {
388
+ $host = $easy->request->getUri()->getHost();
389
+ if (!isset($options['proxy']['no']) ||
390
+ !\GuzzleHttp\is_host_in_noproxy($host, $options['proxy']['no'])
391
+ ) {
392
+ $conf[CURLOPT_PROXY] = $options['proxy'][$scheme];
393
+ }
394
+ }
395
+ }
396
+ }
397
+
398
+ if (isset($options['cert'])) {
399
+ $cert = $options['cert'];
400
+ if (is_array($cert)) {
401
+ $conf[CURLOPT_SSLCERTPASSWD] = $cert[1];
402
+ $cert = $cert[0];
403
+ }
404
+ if (!file_exists($cert)) {
405
+ throw new \InvalidArgumentException(
406
+ "SSL certificate not found: {$cert}"
407
+ );
408
+ }
409
+ $conf[CURLOPT_SSLCERT] = $cert;
410
+ }
411
+
412
+ if (isset($options['ssl_key'])) {
413
+ $sslKey = $options['ssl_key'];
414
+ if (is_array($sslKey)) {
415
+ $conf[CURLOPT_SSLKEYPASSWD] = $sslKey[1];
416
+ $sslKey = $sslKey[0];
417
+ }
418
+ if (!file_exists($sslKey)) {
419
+ throw new \InvalidArgumentException(
420
+ "SSL private key not found: {$sslKey}"
421
+ );
422
+ }
423
+ $conf[CURLOPT_SSLKEY] = $sslKey;
424
+ }
425
+
426
+ if (isset($options['progress'])) {
427
+ $progress = $options['progress'];
428
+ if (!is_callable($progress)) {
429
+ throw new \InvalidArgumentException(
430
+ 'progress client option must be callable'
431
+ );
432
+ }
433
+ $conf[CURLOPT_NOPROGRESS] = false;
434
+ $conf[CURLOPT_PROGRESSFUNCTION] = function () use ($progress) {
435
+ $args = func_get_args();
436
+ // PHP 5.5 pushed the handle onto the start of the args
437
+ if (is_resource($args[0])) {
438
+ array_shift($args);
439
+ }
440
+ call_user_func_array($progress, $args);
441
+ };
442
+ }
443
+
444
+ if (!empty($options['debug'])) {
445
+ $conf[CURLOPT_STDERR] = \GuzzleHttp\debug_resource($options['debug']);
446
+ $conf[CURLOPT_VERBOSE] = true;
447
+ }
448
+ }
449
+
450
+ /**
451
+ * This function ensures that a response was set on a transaction. If one
452
+ * was not set, then the request is retried if possible. This error
453
+ * typically means you are sending a payload, curl encountered a
454
+ * "Connection died, retrying a fresh connect" error, tried to rewind the
455
+ * stream, and then encountered a "necessary data rewind wasn't possible"
456
+ * error, causing the request to be sent through curl_multi_info_read()
457
+ * without an error status.
458
+ */
459
+ private static function retryFailedRewind(
460
+ callable $handler,
461
+ EasyHandle $easy,
462
+ array $ctx
463
+ ) {
464
+ try {
465
+ // Only rewind if the body has been read from.
466
+ $body = $easy->request->getBody();
467
+ if ($body->tell() > 0) {
468
+ $body->rewind();
469
+ }
470
+ } catch (\RuntimeException $e) {
471
+ $ctx['error'] = 'The connection unexpectedly failed without '
472
+ . 'providing an error. The request would have been retried, '
473
+ . 'but attempting to rewind the request body failed. '
474
+ . 'Exception: ' . $e;
475
+ return self::createRejection($easy, $ctx);
476
+ }
477
+
478
+ // Retry no more than 3 times before giving up.
479
+ if (!isset($easy->options['_curl_retries'])) {
480
+ $easy->options['_curl_retries'] = 1;
481
+ } elseif ($easy->options['_curl_retries'] == 2) {
482
+ $ctx['error'] = 'The cURL request was retried 3 times '
483
+ . 'and did not succeed. The most likely reason for the failure '
484
+ . 'is that cURL was unable to rewind the body of the request '
485
+ . 'and subsequent retries resulted in the same error. Turn on '
486
+ . 'the debug option to see what went wrong. See '
487
+ . 'https://bugs.php.net/bug.php?id=47204 for more information.';
488
+ return self::createRejection($easy, $ctx);
489
+ } else {
490
+ $easy->options['_curl_retries']++;
491
+ }
492
+
493
+ return $handler($easy->request, $easy->options);
494
+ }
495
+
496
+ private function createHeaderFn(EasyHandle $easy)
497
+ {
498
+ if (isset($easy->options['on_headers'])) {
499
+ $onHeaders = $easy->options['on_headers'];
500
+
501
+ if (!is_callable($onHeaders)) {
502
+ throw new \InvalidArgumentException('on_headers must be callable');
503
+ }
504
+ } else {
505
+ $onHeaders = null;
506
+ }
507
+
508
+ return function ($ch, $h) use (
509
+ $onHeaders,
510
+ $easy,
511
+ &$startingResponse
512
+ ) {
513
+ $value = trim($h);
514
+ if ($value === '') {
515
+ $startingResponse = true;
516
+ $easy->createResponse();
517
+ if ($onHeaders !== null) {
518
+ try {
519
+ $onHeaders($easy->response);
520
+ } catch (\Exception $e) {
521
+ // Associate the exception with the handle and trigger
522
+ // a curl header write error by returning 0.
523
+ $easy->onHeadersException = $e;
524
+ return -1;
525
+ }
526
+ }
527
+ } elseif ($startingResponse) {
528
+ $startingResponse = false;
529
+ $easy->headers = [$value];
530
+ } else {
531
+ $easy->headers[] = $value;
532
+ }
533
+ return strlen($h);
534
+ };
535
+ }
536
+ }
lib/Azure/GuzzleHttp/Handler/CurlFactoryInterface.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+
6
+ interface CurlFactoryInterface
7
+ {
8
+ /**
9
+ * Creates a cURL handle resource.
10
+ *
11
+ * @param RequestInterface $request Request
12
+ * @param array $options Transfer options
13
+ *
14
+ * @return EasyHandle
15
+ * @throws \RuntimeException when an option cannot be applied
16
+ */
17
+ public function create(RequestInterface $request, array $options);
18
+
19
+ /**
20
+ * Release an easy handle, allowing it to be reused or closed.
21
+ *
22
+ * This function must call unset on the easy handle's "handle" property.
23
+ *
24
+ * @param EasyHandle $easy
25
+ */
26
+ public function release(EasyHandle $easy);
27
+ }
lib/Azure/GuzzleHttp/Handler/CurlHandler.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Psr7;
5
+ use Psr\Http\Message\RequestInterface;
6
+
7
+ /**
8
+ * HTTP handler that uses cURL easy handles as a transport layer.
9
+ *
10
+ * When using the CurlHandler, custom curl options can be specified as an
11
+ * associative array of curl option constants mapping to values in the
12
+ * **curl** key of the "client" key of the request.
13
+ */
14
+ class CurlHandler
15
+ {
16
+ /** @var CurlFactoryInterface */
17
+ private $factory;
18
+
19
+ /**
20
+ * Accepts an associative array of options:
21
+ *
22
+ * - factory: Optional curl factory used to create cURL handles.
23
+ *
24
+ * @param array $options Array of options to use with the handler
25
+ */
26
+ public function __construct(array $options = [])
27
+ {
28
+ $this->factory = isset($options['handle_factory'])
29
+ ? $options['handle_factory']
30
+ : new CurlFactory(3);
31
+ }
32
+
33
+ public function __invoke(RequestInterface $request, array $options)
34
+ {
35
+ if (isset($options['delay'])) {
36
+ usleep($options['delay'] * 1000);
37
+ }
38
+
39
+ $easy = $this->factory->create($request, $options);
40
+ curl_exec($easy->handle);
41
+ $easy->errno = curl_errno($easy->handle);
42
+
43
+ return CurlFactory::finish($this, $easy, $this->factory);
44
+ }
45
+ }
lib/Azure/GuzzleHttp/Handler/CurlMultiHandler.php ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Promise as P;
5
+ use GuzzleHttp\Promise\Promise;
6
+ use GuzzleHttp\Psr7;
7
+ use Psr\Http\Message\RequestInterface;
8
+
9
+ /**
10
+ * Returns an asynchronous response using curl_multi_* functions.
11
+ *
12
+ * When using the CurlMultiHandler, custom curl options can be specified as an
13
+ * associative array of curl option constants mapping to values in the
14
+ * **curl** key of the provided request options.
15
+ *
16
+ * @property resource $_mh Internal use only. Lazy loaded multi-handle.
17
+ */
18
+ class CurlMultiHandler
19
+ {
20
+ /** @var CurlFactoryInterface */
21
+ private $factory;
22
+ private $selectTimeout;
23
+ private $active;
24
+ private $handles = [];
25
+ private $delays = [];
26
+
27
+ /**
28
+ * This handler accepts the following options:
29
+ *
30
+ * - handle_factory: An optional factory used to create curl handles
31
+ * - select_timeout: Optional timeout (in seconds) to block before timing
32
+ * out while selecting curl handles. Defaults to 1 second.
33
+ *
34
+ * @param array $options
35
+ */
36
+ public function __construct(array $options = [])
37
+ {
38
+ $this->factory = isset($options['handle_factory'])
39
+ ? $options['handle_factory'] : new CurlFactory(50);
40
+ $this->selectTimeout = isset($options['select_timeout'])
41
+ ? $options['select_timeout'] : 1;
42
+ }
43
+
44
+ public function __get($name)
45
+ {
46
+ if ($name === '_mh') {
47
+ return $this->_mh = curl_multi_init();
48
+ }
49
+
50
+ throw new \BadMethodCallException();
51
+ }
52
+
53
+ public function __destruct()
54
+ {
55
+ if (isset($this->_mh)) {
56
+ curl_multi_close($this->_mh);
57
+ unset($this->_mh);
58
+ }
59
+ }
60
+
61
+ public function __invoke(RequestInterface $request, array $options)
62
+ {
63
+ $easy = $this->factory->create($request, $options);
64
+ $id = (int) $easy->handle;
65
+
66
+ $promise = new Promise(
67
+ [$this, 'execute'],
68
+ function () use ($id) { return $this->cancel($id); }
69
+ );
70
+
71
+ $this->addRequest(['easy' => $easy, 'deferred' => $promise]);
72
+
73
+ return $promise;
74
+ }
75
+
76
+ /**
77
+ * Ticks the curl event loop.
78
+ */
79
+ public function tick()
80
+ {
81
+ // Add any delayed handles if needed.
82
+ if ($this->delays) {
83
+ $currentTime = microtime(true);
84
+ foreach ($this->delays as $id => $delay) {
85
+ if ($currentTime >= $delay) {
86
+ unset($this->delays[$id]);
87
+ curl_multi_add_handle(
88
+ $this->_mh,
89
+ $this->handles[$id]['easy']->handle
90
+ );
91
+ }
92
+ }
93
+ }
94
+
95
+ // Step through the task queue which may add additional requests.
96
+ P\queue()->run();
97
+
98
+ if ($this->active &&
99
+ curl_multi_select($this->_mh, $this->selectTimeout) === -1
100
+ ) {
101
+ // Perform a usleep if a select returns -1.
102
+ // See: https://bugs.php.net/bug.php?id=61141
103
+ usleep(250);
104
+ }
105
+
106
+ while (curl_multi_exec($this->_mh, $this->active) === CURLM_CALL_MULTI_PERFORM);
107
+
108
+ $this->processMessages();
109
+ }
110
+
111
+ /**
112
+ * Runs until all outstanding connections have completed.
113
+ */
114
+ public function execute()
115
+ {
116
+ $queue = P\queue();
117
+
118
+ while ($this->handles || !$queue->isEmpty()) {
119
+ // If there are no transfers, then sleep for the next delay
120
+ if (!$this->active && $this->delays) {
121
+ usleep($this->timeToNext());
122
+ }
123
+ $this->tick();
124
+ }
125
+ }
126
+
127
+ private function addRequest(array $entry)
128
+ {
129
+ $easy = $entry['easy'];
130
+ $id = (int) $easy->handle;
131
+ $this->handles[$id] = $entry;
132
+ if (empty($easy->options['delay'])) {
133
+ curl_multi_add_handle($this->_mh, $easy->handle);
134
+ } else {
135
+ $this->delays[$id] = microtime(true) + ($easy->options['delay'] / 1000);
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Cancels a handle from sending and removes references to it.
141
+ *
142
+ * @param int $id Handle ID to cancel and remove.
143
+ *
144
+ * @return bool True on success, false on failure.
145
+ */
146
+ private function cancel($id)
147
+ {
148
+ // Cannot cancel if it has been processed.
149
+ if (!isset($this->handles[$id])) {
150
+ return false;
151
+ }
152
+
153
+ $handle = $this->handles[$id]['easy']->handle;
154
+ unset($this->delays[$id], $this->handles[$id]);
155
+ curl_multi_remove_handle($this->_mh, $handle);
156
+ curl_close($handle);
157
+
158
+ return true;
159
+ }
160
+
161
+ private function processMessages()
162
+ {
163
+ while ($done = curl_multi_info_read($this->_mh)) {
164
+ $id = (int) $done['handle'];
165
+ curl_multi_remove_handle($this->_mh, $done['handle']);
166
+
167
+ if (!isset($this->handles[$id])) {
168
+ // Probably was cancelled.
169
+ continue;
170
+ }
171
+
172
+ $entry = $this->handles[$id];
173
+ unset($this->handles[$id], $this->delays[$id]);
174
+ $entry['easy']->errno = $done['result'];
175
+ $entry['deferred']->resolve(
176
+ CurlFactory::finish(
177
+ $this,
178
+ $entry['easy'],
179
+ $this->factory
180
+ )
181
+ );
182
+ }
183
+ }
184
+
185
+ private function timeToNext()
186
+ {
187
+ $currentTime = microtime(true);
188
+ $nextTime = PHP_INT_MAX;
189
+ foreach ($this->delays as $time) {
190
+ if ($time < $nextTime) {
191
+ $nextTime = $time;
192
+ }
193
+ }
194
+
195
+ return max(0, $nextTime - $currentTime) * 1000000;
196
+ }
197
+ }
lib/Azure/GuzzleHttp/Handler/EasyHandle.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Psr7\Response;
5
+ use Psr\Http\Message\RequestInterface;
6
+ use Psr\Http\Message\ResponseInterface;
7
+ use Psr\Http\Message\StreamInterface;
8
+
9
+ /**
10
+ * Represents a cURL easy handle and the data it populates.
11
+ *
12
+ * @internal
13
+ */
14
+ final class EasyHandle
15
+ {
16
+ /** @var resource cURL resource */
17
+ public $handle;
18
+
19
+ /** @var StreamInterface Where data is being written */
20
+ public $sink;
21
+
22
+ /** @var array Received HTTP headers so far */
23
+ public $headers = [];
24
+
25
+ /** @var ResponseInterface Received response (if any) */
26
+ public $response;
27
+
28
+ /** @var RequestInterface Request being sent */
29
+ public $request;
30
+
31
+ /** @var array Request options */
32
+ public $options = [];
33
+
34
+ /** @var int cURL error number (if any) */
35
+ public $errno = 0;
36
+
37
+ /** @var \Exception Exception during on_headers (if any) */
38
+ public $onHeadersException;
39
+
40
+ /**
41
+ * Attach a response to the easy handle based on the received headers.
42
+ *
43
+ * @throws \RuntimeException if no headers have been received.
44
+ */
45
+ public function createResponse()
46
+ {
47
+ if (empty($this->headers)) {
48
+ throw new \RuntimeException('No headers have been received');
49
+ }
50
+
51
+ // HTTP-version SP status-code SP reason-phrase
52
+ $startLine = explode(' ', array_shift($this->headers), 3);
53
+ $headers = \GuzzleHttp\headers_from_lines($this->headers);
54
+ $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
55
+
56
+ if (!empty($this->options['decode_content'])
57
+ && isset($normalizedKeys['content-encoding'])
58
+ ) {
59
+ $headers['x-encoded-content-encoding']
60
+ = $headers[$normalizedKeys['content-encoding']];
61
+ unset($headers[$normalizedKeys['content-encoding']]);
62
+ if (isset($normalizedKeys['content-length'])) {
63
+ $headers['x-encoded-content-length']
64
+ = $headers[$normalizedKeys['content-length']];
65
+
66
+ $bodyLength = (int) $this->sink->getSize();
67
+ if ($bodyLength) {
68
+ $headers[$normalizedKeys['content-length']] = $bodyLength;
69
+ } else {
70
+ unset($headers[$normalizedKeys['content-length']]);
71
+ }
72
+ }
73
+ }
74
+
75
+ // Attach a response to the easy handle with the parsed headers.
76
+ $this->response = new Response(
77
+ $startLine[1],
78
+ $headers,
79
+ $this->sink,
80
+ substr($startLine[0], 5),
81
+ isset($startLine[2]) ? (string) $startLine[2] : null
82
+ );
83
+ }
84
+
85
+ public function __get($name)
86
+ {
87
+ $msg = $name === 'handle'
88
+ ? 'The EasyHandle has been released'
89
+ : 'Invalid property: ' . $name;
90
+ throw new \BadMethodCallException($msg);
91
+ }
92
+ }
lib/Azure/GuzzleHttp/Handler/MockHandler.php ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\HandlerStack;
5
+ use GuzzleHttp\Promise\PromiseInterface;
6
+ use GuzzleHttp\Promise\RejectedPromise;
7
+ use GuzzleHttp\TransferStats;
8
+ use Psr\Http\Message\RequestInterface;
9
+ use Psr\Http\Message\ResponseInterface;
10
+
11
+ /**
12
+ * Handler that returns responses or throw exceptions from a queue.
13
+ */
14
+ class MockHandler implements \Countable
15
+ {
16
+ private $queue;
17
+ private $lastRequest;
18
+ private $lastOptions;
19
+ private $onFulfilled;
20
+ private $onRejected;
21
+
22
+ /**
23
+ * Creates a new MockHandler that uses the default handler stack list of
24
+ * middlewares.
25
+ *
26
+ * @param array $queue Array of responses, callables, or exceptions.
27
+ * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
28
+ * @param callable $onRejected Callback to invoke when the return value is rejected.
29
+ *
30
+ * @return HandlerStack
31
+ */
32
+ public static function createWithMiddleware(
33
+ array $queue = null,
34
+ callable $onFulfilled = null,
35
+ callable $onRejected = null
36
+ ) {
37
+ return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));
38
+ }
39
+
40
+ /**
41
+ * The passed in value must be an array of
42
+ * {@see Psr7\Http\Message\ResponseInterface} objects, Exceptions,
43
+ * callables, or Promises.
44
+ *
45
+ * @param array $queue
46
+ * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
47
+ * @param callable $onRejected Callback to invoke when the return value is rejected.
48
+ */
49
+ public function __construct(
50
+ array $queue = null,
51
+ callable $onFulfilled = null,
52
+ callable $onRejected = null
53
+ ) {
54
+ $this->onFulfilled = $onFulfilled;
55
+ $this->onRejected = $onRejected;
56
+
57
+ if ($queue) {
58
+ call_user_func_array([$this, 'append'], $queue);
59
+ }
60
+ }
61
+
62
+ public function __invoke(RequestInterface $request, array $options)
63
+ {
64
+ if (!$this->queue) {
65
+ throw new \OutOfBoundsException('Mock queue is empty');
66
+ }
67
+
68
+ if (isset($options['delay'])) {
69
+ usleep($options['delay'] * 1000);
70
+ }
71
+
72
+ $this->lastRequest = $request;
73
+ $this->lastOptions = $options;
74
+ $response = array_shift($this->queue);
75
+
76
+ if (is_callable($response)) {
77
+ $response = call_user_func($response, $request, $options);
78
+ }
79
+
80
+ $response = $response instanceof \Exception
81
+ ? new RejectedPromise($response)
82
+ : \GuzzleHttp\Promise\promise_for($response);
83
+
84
+ return $response->then(
85
+ function ($value) use ($request, $options) {
86
+ $this->invokeStats($request, $options, $value);
87
+ if ($this->onFulfilled) {
88
+ call_user_func($this->onFulfilled, $value);
89
+ }
90
+ if (isset($options['sink'])) {
91
+ $contents = (string) $value->getBody();
92
+ $sink = $options['sink'];
93
+
94
+ if (is_resource($sink)) {
95
+ fwrite($sink, $contents);
96
+ } elseif (is_string($sink)) {
97
+ file_put_contents($sink, $contents);
98
+ } elseif ($sink instanceof \Psr\Http\Message\StreamInterface) {
99
+ $sink->write($contents);
100
+ }
101
+ }
102
+
103
+ return $value;
104
+ },
105
+ function ($reason) use ($request, $options) {
106
+ $this->invokeStats($request, $options, null, $reason);
107
+ if ($this->onRejected) {
108
+ call_user_func($this->onRejected, $reason);
109
+ }
110
+ return new RejectedPromise($reason);
111
+ }
112
+ );
113
+ }
114
+
115
+ /**
116
+ * Adds one or more variadic requests, exceptions, callables, or promises
117
+ * to the queue.
118
+ */
119
+ public function append()
120
+ {
121
+ foreach (func_get_args() as $value) {
122
+ if ($value instanceof ResponseInterface
123
+ || $value instanceof \Exception
124
+ || $value instanceof PromiseInterface
125
+ || is_callable($value)
126
+ ) {
127
+ $this->queue[] = $value;
128
+ } else {
129
+ throw new \InvalidArgumentException('Expected a response or '
130
+ . 'exception. Found ' . \GuzzleHttp\describe_type($value));
131
+ }
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Get the last received request.
137
+ *
138
+ * @return RequestInterface
139
+ */
140
+ public function getLastRequest()
141
+ {
142
+ return $this->lastRequest;
143
+ }
144
+
145
+ /**
146
+ * Get the last received request options.
147
+ *
148
+ * @return RequestInterface
149
+ */
150
+ public function getLastOptions()
151
+ {
152
+ return $this->lastOptions;
153
+ }
154
+
155
+ /**
156
+ * Returns the number of remaining items in the queue.
157
+ *
158
+ * @return int
159
+ */
160
+ public function count()
161
+ {
162
+ return count($this->queue);
163
+ }
164
+
165
+ private function invokeStats(
166
+ RequestInterface $request,
167
+ array $options,
168
+ ResponseInterface $response = null,
169
+ $reason = null
170
+ ) {
171
+ if (isset($options['on_stats'])) {
172
+ $stats = new TransferStats($request, $response, 0, $reason);
173
+ call_user_func($options['on_stats'], $stats);
174
+ }
175
+ }
176
+ }
lib/Azure/GuzzleHttp/Handler/Proxy.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\RequestOptions;
5
+ use Psr\Http\Message\RequestInterface;
6
+
7
+ /**
8
+ * Provides basic proxies for handlers.
9
+ */
10
+ class Proxy
11
+ {
12
+ /**
13
+ * Sends synchronous requests to a specific handler while sending all other
14
+ * requests to another handler.
15
+ *
16
+ * @param callable $default Handler used for normal responses
17
+ * @param callable $sync Handler used for synchronous responses.
18
+ *
19
+ * @return callable Returns the composed handler.
20
+ */
21
+ public static function wrapSync(
22
+ callable $default,
23
+ callable $sync
24
+ ) {
25
+ return function (RequestInterface $request, array $options) use ($default, $sync) {
26
+ return empty($options[RequestOptions::SYNCHRONOUS])
27
+ ? $default($request, $options)
28
+ : $sync($request, $options);
29
+ };
30
+ }
31
+
32
+ /**
33
+ * Sends streaming requests to a streaming compatible handler while sending
34
+ * all other requests to a default handler.
35
+ *
36
+ * This, for example, could be useful for taking advantage of the
37
+ * performance benefits of curl while still supporting true streaming
38
+ * through the StreamHandler.
39
+ *
40
+ * @param callable $default Handler used for non-streaming responses
41
+ * @param callable $streaming Handler used for streaming responses
42
+ *
43
+ * @return callable Returns the composed handler.
44
+ */
45
+ public static function wrapStreaming(
46
+ callable $default,
47
+ callable $streaming
48
+ ) {
49
+ return function (RequestInterface $request, array $options) use ($default, $streaming) {
50
+ return empty($options['stream'])
51
+ ? $default($request, $options)
52
+ : $streaming($request, $options);
53
+ };
54
+ }
55
+ }
lib/Azure/GuzzleHttp/Handler/StreamHandler.php ADDED
@@ -0,0 +1,490 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Handler;
3
+
4
+ use GuzzleHttp\Exception\RequestException;
5
+ use GuzzleHttp\Exception\ConnectException;
6
+ use GuzzleHttp\Promise\FulfilledPromise;
7
+ use GuzzleHttp\Promise\RejectedPromise;
8
+ use GuzzleHttp\Promise\PromiseInterface;
9
+ use GuzzleHttp\Psr7;
10
+ use GuzzleHttp\TransferStats;
11
+ use Psr\Http\Message\RequestInterface;
12
+ use Psr\Http\Message\ResponseInterface;
13
+ use Psr\Http\Message\StreamInterface;
14
+
15
+ /**
16
+ * HTTP handler that uses PHP's HTTP stream wrapper.
17
+ */
18
+ class StreamHandler
19
+ {
20
+ private $lastHeaders = [];
21
+
22
+ /**
23
+ * Sends an HTTP request.
24
+ *
25
+ * @param RequestInterface $request Request to send.
26
+ * @param array $options Request transfer options.
27
+ *
28
+ * @return PromiseInterface
29
+ */
30
+ public function __invoke(RequestInterface $request, array $options)
31
+ {
32
+ // Sleep if there is a delay specified.
33
+ if (isset($options['delay'])) {
34
+ usleep($options['delay'] * 1000);
35
+ }
36
+
37
+ $startTime = isset($options['on_stats']) ? microtime(true) : null;
38
+
39
+ try {
40
+ // Does not support the expect header.
41
+ $request = $request->withoutHeader('Expect');
42
+
43
+ // Append a content-length header if body size is zero to match
44
+ // cURL's behavior.
45
+ if (0 === $request->getBody()->getSize()) {
46
+ $request = $request->withHeader('Content-Length', 0);
47
+ }
48
+
49
+ return $this->createResponse(
50
+ $request,
51
+ $options,
52
+ $this->createStream($request, $options),
53
+ $startTime
54
+ );
55
+ } catch (\InvalidArgumentException $e) {
56
+ throw $e;
57
+ } catch (\Exception $e) {
58
+ // Determine if the error was a networking error.
59
+ $message = $e->getMessage();
60
+ // This list can probably get more comprehensive.
61
+ if (strpos($message, 'getaddrinfo') // DNS lookup failed
62
+ || strpos($message, 'Connection refused')
63
+ || strpos($message, "couldn't connect to host") // error on HHVM
64
+ ) {
65
+ $e = new ConnectException($e->getMessage(), $request, $e);
66
+ }
67
+ $e = RequestException::wrapException($request, $e);
68
+ $this->invokeStats($options, $request, $startTime, null, $e);
69
+
70
+ return new RejectedPromise($e);
71
+ }
72
+ }
73
+
74
+ private function invokeStats(
75
+ array $options,
76
+ RequestInterface $request,
77
+ $startTime,
78
+ ResponseInterface $response = null,
79
+ $error = null
80
+ ) {
81
+ if (isset($options['on_stats'])) {
82
+ $stats = new TransferStats(
83
+ $request,
84
+ $response,
85
+ microtime(true) - $startTime,
86
+ $error,
87
+ []
88
+ );
89
+ call_user_func($options['on_stats'], $stats);
90
+ }
91
+ }
92
+
93
+ private function createResponse(
94
+ RequestInterface $request,
95
+ array $options,
96
+ $stream,
97
+ $startTime
98
+ ) {
99
+ $hdrs = $this->lastHeaders;
100
+ $this->lastHeaders = [];
101
+ $parts = explode(' ', array_shift($hdrs), 3);
102
+ $ver = explode('/', $parts[0])[1];
103
+ $status = $parts[1];
104
+ $reason = isset($parts[2]) ? $parts[2] : null;
105
+ $headers = \GuzzleHttp\headers_from_lines($hdrs);
106
+ list ($stream, $headers) = $this->checkDecode($options, $headers, $stream);
107
+ $stream = Psr7\stream_for($stream);
108
+ $sink = $stream;
109
+
110
+ if (strcasecmp('HEAD', $request->getMethod())) {
111
+ $sink = $this->createSink($stream, $options);
112
+ }
113
+
114
+ $response = new Psr7\Response($status, $headers, $sink, $ver, $reason);
115
+
116
+ if (isset($options['on_headers'])) {
117
+ try {
118
+ $options['on_headers']($response);
119
+ } catch (\Exception $e) {
120
+ $msg = 'An error was encountered during the on_headers event';
121
+ $ex = new RequestException($msg, $request, $response, $e);
122
+ return new RejectedPromise($ex);
123
+ }
124
+ }
125
+
126
+ // Do not drain when the request is a HEAD request because they have
127
+ // no body.
128
+ if ($sink !== $stream) {
129
+ $this->drain(
130
+ $stream,
131
+ $sink,
132
+ $response->getHeaderLine('Content-Length')
133
+ );
134
+ }
135
+
136
+ $this->invokeStats($options, $request, $startTime, $response, null);
137
+
138
+ return new FulfilledPromise($response);
139
+ }
140
+
141
+ private function createSink(StreamInterface $stream, array $options)
142
+ {
143
+ if (!empty($options['stream'])) {
144
+ return $stream;
145
+ }
146
+
147
+ $sink = isset($options['sink'])
148
+ ? $options['sink']
149
+ : fopen('php://temp', 'r+');
150
+
151
+ return is_string($sink)
152
+ ? new Psr7\LazyOpenStream($sink, 'w+')
153
+ : Psr7\stream_for($sink);
154
+ }
155
+
156
+ private function checkDecode(array $options, array $headers, $stream)
157
+ {
158
+ // Automatically decode responses when instructed.
159
+ if (!empty($options['decode_content'])) {
160
+ $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
161
+ if (isset($normalizedKeys['content-encoding'])) {
162
+ $encoding = $headers[$normalizedKeys['content-encoding']];
163
+ if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') {
164
+ $stream = new Psr7\InflateStream(
165
+ Psr7\stream_for($stream)
166
+ );
167
+ $headers['x-encoded-content-encoding']
168
+ = $headers[$normalizedKeys['content-encoding']];
169
+ // Remove content-encoding header
170
+ unset($headers[$normalizedKeys['content-encoding']]);
171
+ // Fix content-length header
172
+ if (isset($normalizedKeys['content-length'])) {
173
+ $headers['x-encoded-content-length']
174
+ = $headers[$normalizedKeys['content-length']];
175
+
176
+ $length = (int) $stream->getSize();
177
+ if ($length === 0) {
178
+ unset($headers[$normalizedKeys['content-length']]);
179
+ } else {
180
+ $headers[$normalizedKeys['content-length']] = [$length];
181
+ }
182
+ }
183
+ }
184
+ }
185
+ }
186
+
187
+ return [$stream, $headers];
188
+ }
189
+
190
+ /**
191
+ * Drains the source stream into the "sink" client option.
192
+ *
193
+ * @param StreamInterface $source
194
+ * @param StreamInterface $sink
195
+ * @param string $contentLength Header specifying the amount of
196
+ * data to read.
197
+ *
198
+ * @return StreamInterface
199
+ * @throws \RuntimeException when the sink option is invalid.
200
+ */
201
+ private function drain(
202
+ StreamInterface $source,
203
+ StreamInterface $sink,
204
+ $contentLength
205
+ ) {
206
+ // If a content-length header is provided, then stop reading once
207
+ // that number of bytes has been read. This can prevent infinitely
208
+ // reading from a stream when dealing with servers that do not honor
209
+ // Connection: Close headers.
210
+ Psr7\copy_to_stream(
211
+ $source,
212
+ $sink,
213
+ (strlen($contentLength) > 0 && (int) $contentLength > 0) ? (int) $contentLength : -1
214
+ );
215
+
216
+ $sink->seek(0);
217
+ $source->close();
218
+
219
+ return $sink;
220
+ }
221
+
222
+ /**
223
+ * Create a resource and check to ensure it was created successfully
224
+ *
225
+ * @param callable $callback Callable that returns stream resource
226
+ *
227
+ * @return resource
228
+ * @throws \RuntimeException on error
229
+ */
230
+ private function createResource(callable $callback)
231
+ {
232
+ $errors = null;
233
+ set_error_handler(function ($_, $msg, $file, $line) use (&$errors) {
234
+ $errors[] = [
235
+ 'message' => $msg,
236
+ 'file' => $file,
237
+ 'line' => $line
238
+ ];
239
+ return true;
240
+ });
241
+
242
+ $resource = $callback();
243
+ restore_error_handler();
244
+
245
+ if (!$resource) {
246
+ $message = 'Error creating resource: ';
247
+ foreach ($errors as $err) {
248
+ foreach ($err as $key => $value) {
249
+ $message .= "[$key] $value" . PHP_EOL;
250
+ }
251
+ }
252
+ throw new \RuntimeException(trim($message));
253
+ }
254
+
255
+ return $resource;
256
+ }
257
+
258
+ private function createStream(RequestInterface $request, array $options)
259
+ {
260
+ static $methods;
261
+ if (!$methods) {
262
+ $methods = array_flip(get_class_methods(__CLASS__));
263
+ }
264
+
265
+ // HTTP/1.1 streams using the PHP stream wrapper require a
266
+ // Connection: close header
267
+ if ($request->getProtocolVersion() == '1.1'
268
+ && !$request->hasHeader('Connection')
269
+ ) {
270
+ $request = $request->withHeader('Connection', 'close');
271
+ }
272
+
273
+ // Ensure SSL is verified by default
274
+ if (!isset($options['verify'])) {
275
+ $options['verify'] = true;
276
+ }
277
+
278
+ $params = [];
279
+ $context = $this->getDefaultContext($request, $options);
280
+
281
+ if (isset($options['on_headers']) && !is_callable($options['on_headers'])) {
282
+ throw new \InvalidArgumentException('on_headers must be callable');
283
+ }
284
+
285
+ if (!empty($options)) {
286
+ foreach ($options as $key => $value) {
287
+ $method = "add_{$key}";
288
+ if (isset($methods[$method])) {
289
+ $this->{$method}($request, $context, $value, $params);
290
+ }
291
+ }
292
+ }
293
+
294
+ if (isset($options['stream_context'])) {
295
+ if (!is_array($options['stream_context'])) {
296
+ throw new \InvalidArgumentException('stream_context must be an array');
297
+ }
298
+ $context = array_replace_recursive(
299
+ $context,
300
+ $options['stream_context']
301
+ );
302
+ }
303
+
304
+ $context = $this->createResource(
305
+ function () use ($context, $params) {
306
+ return stream_context_create($context, $params);
307
+ }
308
+ );
309
+
310
+ return $this->createResource(
311
+ function () use ($request, &$http_response_header, $context) {
312
+ $resource = fopen((string) $request->getUri()->withFragment(''), 'r', null, $context);
313
+ $this->lastHeaders = $http_response_header;
314
+ return $resource;
315
+ }
316
+ );
317
+ }
318
+
319
+ private function getDefaultContext(RequestInterface $request)
320
+ {
321
+ $headers = '';
322
+ foreach ($request->getHeaders() as $name => $value) {
323
+ foreach ($value as $val) {
324
+ $headers .= "$name: $val\r\n";
325
+ }
326
+ }
327
+
328
+ $context = [
329
+ 'http' => [
330
+ 'method' => $request->getMethod(),
331
+ 'header' => $headers,
332
+ 'protocol_version' => $request->getProtocolVersion(),
333
+ 'ignore_errors' => true,
334
+ 'follow_location' => 0,
335
+ ],
336
+ ];
337
+
338
+ $body = (string) $request->getBody();
339
+
340
+ if (!empty($body)) {
341
+ $context['http']['content'] = $body;
342
+ // Prevent the HTTP handler from adding a Content-Type header.
343
+ if (!$request->hasHeader('Content-Type')) {
344
+ $context['http']['header'] .= "Content-Type:\r\n";
345
+ }
346
+ }
347
+
348
+ $context['http']['header'] = rtrim($context['http']['header']);
349
+
350
+ return $context;
351
+ }
352
+
353
+ private function add_proxy(RequestInterface $request, &$options, $value, &$params)
354
+ {
355
+ if (!is_array($value)) {
356
+ $options['http']['proxy'] = $value;
357
+ } else {
358
+ $scheme = $request->getUri()->getScheme();
359
+ if (isset($value[$scheme])) {
360
+ if (!isset($value['no'])
361
+ || !\GuzzleHttp\is_host_in_noproxy(
362
+ $request->getUri()->getHost(),
363
+ $value['no']
364
+ )
365
+ ) {
366
+ $options['http']['proxy'] = $value[$scheme];
367
+ }
368
+ }
369
+ }
370
+ }
371
+
372
+ private function add_timeout(RequestInterface $request, &$options, $value, &$params)
373
+ {
374
+ if ($value > 0) {
375
+ $options['http']['timeout'] = $value;
376
+ }
377
+ }
378
+
379
+ private function add_verify(RequestInterface $request, &$options, $value, &$params)
380
+ {
381
+ if ($value === true) {
382
+ // PHP 5.6 or greater will find the system cert by default. When
383
+ // < 5.6, use the Guzzle bundled cacert.
384
+ if (PHP_VERSION_ID < 50600) {
385
+ $options['ssl']['cafile'] = \GuzzleHttp\default_ca_bundle();
386
+ }
387
+ } elseif (is_string($value)) {
388
+ $options['ssl']['cafile'] = $value;
389
+ if (!file_exists($value)) {
390
+ throw new \RuntimeException("SSL CA bundle not found: $value");
391
+ }
392
+ } elseif ($value === false) {
393
+ $options['ssl']['verify_peer'] = false;
394
+ $options['ssl']['verify_peer_name'] = false;
395
+ return;
396
+ } else {
397
+ throw new \InvalidArgumentException('Invalid verify request option');
398
+ }
399
+
400
+ $options['ssl']['verify_peer'] = true;
401
+ $options['ssl']['verify_peer_name'] = true;
402
+ $options['ssl']['allow_self_signed'] = false;
403
+ }
404
+
405
+ private function add_cert(RequestInterface $request, &$options, $value, &$params)
406
+ {
407
+ if (is_array($value)) {
408
+ $options['ssl']['passphrase'] = $value[1];
409
+ $value = $value[0];
410
+ }
411
+
412
+ if (!file_exists($value)) {
413
+ throw new \RuntimeException("SSL certificate not found: {$value}");
414
+ }
415
+
416
+ $options['ssl']['local_cert'] = $value;
417
+ }
418
+
419
+ private function add_progress(RequestInterface $request, &$options, $value, &$params)
420
+ {
421
+ $this->addNotification(
422
+ $params,
423
+ function ($code, $a, $b, $c, $transferred, $total) use ($value) {
424
+ if ($code == STREAM_NOTIFY_PROGRESS) {
425
+ $value($total, $transferred, null, null);
426
+ }
427
+ }
428
+ );
429
+ }
430
+
431
+ private function add_debug(RequestInterface $request, &$options, $value, &$params)
432
+ {
433
+ if ($value === false) {
434
+ return;
435
+ }
436
+
437
+ static $map = [
438
+ STREAM_NOTIFY_CONNECT => 'CONNECT',
439
+ STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
440
+ STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
441
+ STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
442
+ STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
443
+ STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
444
+ STREAM_NOTIFY_PROGRESS => 'PROGRESS',
445
+ STREAM_NOTIFY_FAILURE => 'FAILURE',
446
+ STREAM_NOTIFY_COMPLETED => 'COMPLETED',
447
+ STREAM_NOTIFY_RESOLVE => 'RESOLVE',
448
+ ];
449
+ static $args = ['severity', 'message', 'message_code',
450
+ 'bytes_transferred', 'bytes_max'];
451
+
452
+ $value = \GuzzleHttp\debug_resource($value);
453
+ $ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');
454
+ $this->addNotification(
455
+ $params,
456
+ function () use ($ident, $value, $map, $args) {
457
+ $passed = func_get_args();
458
+ $code = array_shift($passed);
459
+ fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
460
+ foreach (array_filter($passed) as $i => $v) {
461
+ fwrite($value, $args[$i] . ': "' . $v . '" ');
462
+ }
463
+ fwrite($value, "\n");
464
+ }
465
+ );
466
+ }
467
+
468
+ private function addNotification(array &$params, callable $notify)
469
+ {
470
+ // Wrap the existing function if needed.
471
+ if (!isset($params['notification'])) {
472
+ $params['notification'] = $notify;
473
+ } else {
474
+ $params['notification'] = $this->callArray([
475
+ $params['notification'],
476
+ $notify
477
+ ]);
478
+ }
479
+ }
480
+
481
+ private function callArray(array $functions)
482
+ {
483
+ return function () use ($functions) {
484
+ $args = func_get_args();
485
+ foreach ($functions as $fn) {
486
+ call_user_func_array($fn, $args);
487
+ }
488
+ };
489
+ }
490
+ }
lib/Azure/GuzzleHttp/HandlerStack.php ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+
6
+ /**
7
+ * Creates a composed Guzzle handler function by stacking middlewares on top of
8
+ * an HTTP handler function.
9
+ */
10
+ class HandlerStack
11
+ {
12
+ /** @var callable */
13
+ private $handler;
14
+
15
+ /** @var array */
16
+ private $stack = [];
17
+
18
+ /** @var callable|null */
19
+ private $cached;
20
+
21
+ /**
22
+ * Creates a default handler stack that can be used by clients.
23
+ *
24
+ * The returned handler will wrap the provided handler or use the most
25
+ * appropriate default handler for you system. The returned HandlerStack has
26
+ * support for cookies, redirects, HTTP error exceptions, and preparing a body
27
+ * before sending.
28
+ *
29
+ * The returned handler stack can be passed to a client in the "handler"
30
+ * option.
31
+ *
32
+ * @param callable $handler HTTP handler function to use with the stack. If no
33
+ * handler is provided, the best handler for your
34
+ * system will be utilized.
35
+ *
36
+ * @return HandlerStack
37
+ */
38
+ public static function create(callable $handler = null)
39
+ {
40
+ $stack = new self($handler ?: choose_handler());
41
+ $stack->push(Middleware::httpErrors(), 'http_errors');
42
+ $stack->push(Middleware::redirect(), 'allow_redirects');
43
+ $stack->push(Middleware::cookies(), 'cookies');
44
+ $stack->push(Middleware::prepareBody(), 'prepare_body');
45
+
46
+ return $stack;
47
+ }
48
+
49
+ /**
50
+ * @param callable $handler Underlying HTTP handler.
51
+ */
52
+ public function __construct(callable $handler = null)
53
+ {
54
+ $this->handler = $handler;
55
+ }
56
+
57
+ /**
58
+ * Invokes the handler stack as a composed handler
59
+ *
60
+ * @param RequestInterface $request
61
+ * @param array $options
62
+ */
63
+ public function __invoke(RequestInterface $request, array $options)
64
+ {
65
+ $handler = $this->resolve();
66
+
67
+ return $handler($request, $options);
68
+ }
69
+
70
+ /**
71
+ * Dumps a string representation of the stack.
72
+ *
73
+ * @return string
74
+ */
75
+ public function __toString()
76
+ {
77
+ $depth = 0;
78
+ $stack = [];
79
+ if ($this->handler) {
80
+ $stack[] = "0) Handler: " . $this->debugCallable($this->handler);
81
+ }
82
+
83
+ $result = '';
84
+ foreach (array_reverse($this->stack) as $tuple) {
85
+ $depth++;
86
+ $str = "{$depth}) Name: '{$tuple[1]}', ";
87
+ $str .= "Function: " . $this->debugCallable($tuple[0]);
88
+ $result = "> {$str}\n{$result}";
89
+ $stack[] = $str;
90
+ }
91
+
92
+ foreach (array_keys($stack) as $k) {
93
+ $result .= "< {$stack[$k]}\n";
94
+ }
95
+
96
+ return $result;
97
+ }
98
+
99
+ /**
100
+ * Set the HTTP handler that actually returns a promise.
101
+ *
102
+ * @param callable $handler Accepts a request and array of options and
103
+ * returns a Promise.
104
+ */
105
+ public function setHandler(callable $handler)
106
+ {
107
+ $this->handler = $handler;
108
+ $this->cached = null;
109
+ }
110
+
111
+ /**
112
+ * Returns true if the builder has a handler.
113
+ *
114
+ * @return bool
115
+ */
116
+ public function hasHandler()
117
+ {
118
+ return (bool) $this->handler;
119
+ }
120
+
121
+ /**
122
+ * Unshift a middleware to the bottom of the stack.
123
+ *
124
+ * @param callable $middleware Middleware function
125
+ * @param string $name Name to register for this middleware.
126
+ */
127
+ public function unshift(callable $middleware, $name = null)
128
+ {
129
+ array_unshift($this->stack, [$middleware, $name]);
130
+ $this->cached = null;
131
+ }
132
+
133
+ /**
134
+ * Push a middleware to the top of the stack.
135
+ *
136
+ * @param callable $middleware Middleware function
137
+ * @param string $name Name to register for this middleware.
138
+ */
139
+ public function push(callable $middleware, $name = '')
140
+ {
141
+ $this->stack[] = [$middleware, $name];
142
+ $this->cached = null;
143
+ }
144
+
145
+ /**
146
+ * Add a middleware before another middleware by name.
147
+ *
148
+ * @param string $findName Middleware to find
149
+ * @param callable $middleware Middleware function
150
+ * @param string $withName Name to register for this middleware.
151
+ */
152
+ public function before($findName, callable $middleware, $withName = '')
153
+ {
154
+ $this->splice($findName, $withName, $middleware, true);
155
+ }
156
+
157
+ /**
158
+ * Add a middleware after another middleware by name.
159
+ *
160
+ * @param string $findName Middleware to find
161
+ * @param callable $middleware Middleware function
162
+ * @param string $withName Name to register for this middleware.
163
+ */
164
+ public function after($findName, callable $middleware, $withName = '')
165
+ {
166
+ $this->splice($findName, $withName, $middleware, false);
167
+ }
168
+
169
+ /**
170
+ * Remove a middleware by instance or name from the stack.
171
+ *
172
+ * @param callable|string $remove Middleware to remove by instance or name.
173
+ */
174
+ public function remove($remove)
175
+ {
176
+ $this->cached = null;
177
+ $idx = is_callable($remove) ? 0 : 1;
178
+ $this->stack = array_values(array_filter(
179
+ $this->stack,
180
+ function ($tuple) use ($idx, $remove) {
181
+ return $tuple[$idx] !== $remove;
182
+ }
183
+ ));
184
+ }
185
+
186
+ /**
187
+ * Compose the middleware and handler into a single callable function.
188
+ *
189
+ * @return callable
190
+ */
191
+ public function resolve()
192
+ {
193
+ if (!$this->cached) {
194
+ if (!($prev = $this->handler)) {
195
+ throw new \LogicException('No handler has been specified');
196
+ }
197
+
198
+ foreach (array_reverse($this->stack) as $fn) {
199
+ $prev = $fn[0]($prev);
200
+ }
201
+
202
+ $this->cached = $prev;
203
+ }
204
+
205
+ return $this->cached;
206
+ }
207
+
208
+ /**
209
+ * @param $name
210
+ * @return int
211
+ */
212
+ private function findByName($name)
213
+ {
214
+ foreach ($this->stack as $k => $v) {
215
+ if ($v[1] === $name) {
216
+ return $k;
217
+ }
218
+ }
219
+
220
+ throw new \InvalidArgumentException("Middleware not found: $name");
221
+ }
222
+
223
+ /**
224
+ * Splices a function into the middleware list at a specific position.
225
+ *
226
+ * @param $findName
227
+ * @param $withName
228
+ * @param callable $middleware
229
+ * @param $before
230
+ */
231
+ private function splice($findName, $withName, callable $middleware, $before)
232
+ {
233
+ $this->cached = null;
234
+ $idx = $this->findByName($findName);
235
+ $tuple = [$middleware, $withName];
236
+
237
+ if ($before) {
238
+ if ($idx === 0) {
239
+ array_unshift($this->stack, $tuple);
240
+ } else {
241
+ $replacement = [$tuple, $this->stack[$idx]];
242
+ array_splice($this->stack, $idx, 1, $replacement);
243
+ }
244
+ } elseif ($idx === count($this->stack) - 1) {
245
+ $this->stack[] = $tuple;
246
+ } else {
247
+ $replacement = [$this->stack[$idx], $tuple];
248
+ array_splice($this->stack, $idx, 1, $replacement);
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Provides a debug string for a given callable.
254
+ *
255
+ * @param array|callable $fn Function to write as a string.
256
+ *
257
+ * @return string
258
+ */
259
+ private function debugCallable($fn)
260
+ {
261
+ if (is_string($fn)) {
262
+ return "callable({$fn})";
263
+ }
264
+
265
+ if (is_array($fn)) {
266
+ return is_string($fn[0])
267
+ ? "callable({$fn[0]}::{$fn[1]})"
268
+ : "callable(['" . get_class($fn[0]) . "', '{$fn[1]}'])";
269
+ }
270
+
271
+ return 'callable(' . spl_object_hash($fn) . ')';
272
+ }
273
+ }
lib/Azure/GuzzleHttp/MessageFormatter.php ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use Psr\Http\Message\MessageInterface;
5
+ use Psr\Http\Message\RequestInterface;
6
+ use Psr\Http\Message\ResponseInterface;
7
+
8
+ /**
9
+ * Formats log messages using variable substitutions for requests, responses,
10
+ * and other transactional data.
11
+ *
12
+ * The following variable substitutions are supported:
13
+ *
14
+ * - {request}: Full HTTP request message
15
+ * - {response}: Full HTTP response message
16
+ * - {ts}: ISO 8601 date in GMT
17
+ * - {date_iso_8601} ISO 8601 date in GMT
18
+ * - {date_common_log} Apache common log date using the configured timezone.
19
+ * - {host}: Host of the request
20
+ * - {method}: Method of the request
21
+ * - {uri}: URI of the request
22
+ * - {host}: Host of the request
23
+ * - {version}: Protocol version
24
+ * - {target}: Request target of the request (path + query + fragment)
25
+ * - {hostname}: Hostname of the machine that sent the request
26
+ * - {code}: Status code of the response (if available)
27
+ * - {phrase}: Reason phrase of the response (if available)
28
+ * - {error}: Any error messages (if available)
29
+ * - {req_header_*}: Replace `*` with the lowercased name of a request header to add to the message
30
+ * - {res_header_*}: Replace `*` with the lowercased name of a response header to add to the message
31
+ * - {req_headers}: Request headers
32
+ * - {res_headers}: Response headers
33
+ * - {req_body}: Request body
34
+ * - {res_body}: Response body
35
+ */
36
+ class MessageFormatter
37
+ {
38
+ /**
39
+ * Apache Common Log Format.
40
+ * @link http://httpd.apache.org/docs/2.4/logs.html#common
41
+ * @var string
42
+ */
43
+ const CLF = "{hostname} {req_header_User-Agent} - [{date_common_log}] \"{method} {target} HTTP/{version}\" {code} {res_header_Content-Length}";
44
+ const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
45
+ const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
46
+
47
+ /** @var string Template used to format log messages */
48
+ private $template;
49
+
50
+ /**
51
+ * @param string $template Log message template
52
+ */
53
+ public function __construct($template = self::CLF)
54
+ {
55
+ $this->template = $template ?: self::CLF;
56
+ }
57
+
58
+ /**
59
+ * Returns a formatted message string.
60
+ *
61
+ * @param RequestInterface $request Request that was sent
62
+ * @param ResponseInterface $response Response that was received
63
+ * @param \Exception $error Exception that was received
64
+ *
65
+ * @return string
66
+ */
67
+ public function format(
68
+ RequestInterface $request,
69
+ ResponseInterface $response = null,
70
+ \Exception $error = null
71
+ ) {
72
+ $cache = [];
73
+
74
+ return preg_replace_callback(
75
+ '/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
76
+ function (array $matches) use ($request, $response, $error, &$cache) {
77
+
78
+ if (isset($cache[$matches[1]])) {
79
+ return $cache[$matches[1]];
80
+ }
81
+
82
+ $result = '';
83
+ switch ($matches[1]) {
84
+ case 'request':
85
+ $result = Psr7\str($request);
86
+ break;
87
+ case 'response':
88
+ $result = $response ? Psr7\str($response) : '';
89
+ break;
90
+ case 'req_headers':
91
+ $result = trim($request->getMethod()
92
+ . ' ' . $request->getRequestTarget())
93
+ . ' HTTP/' . $request->getProtocolVersion() . "\r\n"
94
+ . $this->headers($request);
95
+ break;
96
+ case 'res_headers':
97
+ $result = $response ?
98
+ sprintf(
99
+ 'HTTP/%s %d %s',
100
+ $response->getProtocolVersion(),
101
+ $response->getStatusCode(),
102
+ $response->getReasonPhrase()
103
+ ) . "\r\n" . $this->headers($response)
104
+ : 'NULL';
105
+ break;
106
+ case 'req_body':
107
+ $result = $request->getBody();
108
+ break;
109
+ case 'res_body':
110
+ $result = $response ? $response->getBody() : 'NULL';
111
+ break;
112
+ case 'ts':
113
+ case 'date_iso_8601':
114
+ $result = gmdate('c');
115
+ break;
116
+ case 'date_common_log':
117
+ $result = date('d/M/Y:H:i:s O');
118
+ break;
119
+ case 'method':
120
+ $result = $request->getMethod();
121
+ break;
122
+ case 'version':
123
+ $result = $request->getProtocolVersion();
124
+ break;
125
+ case 'uri':
126
+ case 'url':
127
+ $result = $request->getUri();
128
+ break;
129
+ case 'target':
130
+ $result = $request->getRequestTarget();
131
+ break;
132
+ case 'req_version':
133
+ $result = $request->getProtocolVersion();
134
+ break;
135
+ case 'res_version':
136
+ $result = $response
137
+ ? $response->getProtocolVersion()
138
+ : 'NULL';
139
+ break;
140
+ case 'host':
141
+ $result = $request->getHeaderLine('Host');
142
+ break;
143
+ case 'hostname':
144
+ $result = gethostname();
145
+ break;
146
+ case 'code':
147
+ $result = $response ? $response->getStatusCode() : 'NULL';
148
+ break;
149
+ case 'phrase':
150
+ $result = $response ? $response->getReasonPhrase() : 'NULL';
151
+ break;
152
+ case 'error':
153
+ $result = $error ? $error->getMessage() : 'NULL';
154
+ break;
155
+ default:
156
+ // handle prefixed dynamic headers
157
+ if (strpos($matches[1], 'req_header_') === 0) {
158
+ $result = $request->getHeaderLine(substr($matches[1], 11));
159
+ } elseif (strpos($matches[1], 'res_header_') === 0) {
160
+ $result = $response
161
+ ? $response->getHeaderLine(substr($matches[1], 11))
162
+ : 'NULL';
163
+ }
164
+ }
165
+
166
+ $cache[$matches[1]] = $result;
167
+ return $result;
168
+ },
169
+ $this->template
170
+ );
171
+ }
172
+
173
+ private function headers(MessageInterface $message)
174
+ {
175
+ $result = '';
176
+ foreach ($message->getHeaders() as $name => $values) {
177
+ $result .= $name . ': ' . implode(', ', $values) . "\r\n";
178
+ }
179
+
180
+ return trim($result);
181
+ }
182
+ }
lib/Azure/GuzzleHttp/Middleware.php ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Cookie\CookieJarInterface;
5
+ use GuzzleHttp\Exception\RequestException;
6
+ use GuzzleHttp\Promise\RejectedPromise;
7
+ use GuzzleHttp\Psr7;
8
+ use Psr\Http\Message\ResponseInterface;
9
+ use Psr\Log\LoggerInterface;
10
+ use Psr\Log\LogLevel;
11
+
12
+ /**
13
+ * Functions used to create and wrap handlers with handler middleware.
14
+ */
15
+ final class Middleware
16
+ {
17
+ /**
18
+ * Middleware that adds cookies to requests.
19
+ *
20
+ * The options array must be set to a CookieJarInterface in order to use
21
+ * cookies. This is typically handled for you by a client.
22
+ *
23
+ * @return callable Returns a function that accepts the next handler.
24
+ */
25
+ public static function cookies()
26
+ {
27
+ return function (callable $handler) {
28
+ return function ($request, array $options) use ($handler) {
29
+ if (empty($options['cookies'])) {
30
+ return $handler($request, $options);
31
+ } elseif (!($options['cookies'] instanceof CookieJarInterface)) {
32
+ throw new \InvalidArgumentException('cookies must be an instance of GuzzleHttp\Cookie\CookieJarInterface');
33
+ }
34
+ $cookieJar = $options['cookies'];
35
+ $request = $cookieJar->withCookieHeader($request);
36
+ return $handler($request, $options)
37
+ ->then(function ($response) use ($cookieJar, $request) {
38
+ $cookieJar->extractCookies($request, $response);
39
+ return $response;
40
+ }
41
+ );
42
+ };
43
+ };
44
+ }
45
+
46
+ /**
47
+ * Middleware that throws exceptions for 4xx or 5xx responses when the
48
+ * "http_error" request option is set to true.
49
+ *
50
+ * @return callable Returns a function that accepts the next handler.
51
+ */
52
+ public static function httpErrors()
53
+ {
54
+ return function (callable $handler) {
55
+ return function ($request, array $options) use ($handler) {
56
+ if (empty($options['http_errors'])) {
57
+ return $handler($request, $options);
58
+ }
59
+ return $handler($request, $options)->then(
60
+ function (ResponseInterface $response) use ($request, $handler) {
61
+ $code = $response->getStatusCode();
62
+ if ($code < 400) {
63
+ return $response;
64
+ }
65
+ throw RequestException::create($request, $response);
66
+ }
67
+ );
68
+ };
69
+ };
70
+ }
71
+
72
+ /**
73
+ * Middleware that pushes history data to an ArrayAccess container.
74
+ *
75
+ * @param array $container Container to hold the history (by reference).
76
+ *
77
+ * @return callable Returns a function that accepts the next handler.
78
+ * @throws \InvalidArgumentException if container is not an array or ArrayAccess.
79
+ */
80
+ public static function history(&$container)
81
+ {
82
+ if (!is_array($container) && !$container instanceof \ArrayAccess) {
83
+ throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess');
84
+ }
85
+
86
+ return function (callable $handler) use (&$container) {
87
+ return function ($request, array $options) use ($handler, &$container) {
88
+ return $handler($request, $options)->then(
89
+ function ($value) use ($request, &$container, $options) {
90
+ $container[] = [
91
+ 'request' => $request,
92
+ 'response' => $value,
93
+ 'error' => null,
94
+ 'options' => $options
95
+ ];
96
+ return $value;
97
+ },
98
+ function ($reason) use ($request, &$container, $options) {
99
+ $container[] = [
100
+ 'request' => $request,
101
+ 'response' => null,
102
+ 'error' => $reason,
103
+ 'options' => $options
104
+ ];
105
+ return new RejectedPromise($reason);
106
+ }
107
+ );
108
+ };
109
+ };
110
+ }
111
+
112
+ /**
113
+ * Middleware that invokes a callback before and after sending a request.
114
+ *
115
+ * The provided listener cannot modify or alter the response. It simply
116
+ * "taps" into the chain to be notified before returning the promise. The
117
+ * before listener accepts a request and options array, and the after
118
+ * listener accepts a request, options array, and response promise.
119
+ *
120
+ * @param callable $before Function to invoke before forwarding the request.
121
+ * @param callable $after Function invoked after forwarding.
122
+ *
123
+ * @return callable Returns a function that accepts the next handler.
124
+ */
125
+ public static function tap(callable $before = null, callable $after = null)
126
+ {
127
+ return function (callable $handler) use ($before, $after) {
128
+ return function ($request, array $options) use ($handler, $before, $after) {
129
+ if ($before) {
130
+ $before($request, $options);
131
+ }
132
+ $response = $handler($request, $options);
133
+ if ($after) {
134
+ $after($request, $options, $response);
135
+ }
136
+ return $response;
137
+ };
138
+ };
139
+ }
140
+
141
+ /**
142
+ * Middleware that handles request redirects.
143
+ *
144
+ * @return callable Returns a function that accepts the next handler.
145
+ */
146
+ public static function redirect()
147
+ {
148
+ return function (callable $handler) {
149
+ return new RedirectMiddleware($handler);
150
+ };
151
+ }
152
+
153
+ /**
154
+ * Middleware that retries requests based on the boolean result of
155
+ * invoking the provided "decider" function.
156
+ *
157
+ * If no delay function is provided, a simple implementation of exponential
158
+ * backoff will be utilized.
159
+ *
160
+ * @param callable $decider Function that accepts the number of retries,
161
+ * a request, [response], and [exception] and
162
+ * returns true if the request is to be retried.
163
+ * @param callable $delay Function that accepts the number of retries and
164
+ * returns the number of milliseconds to delay.
165
+ *
166
+ * @return callable Returns a function that accepts the next handler.
167
+ */
168
+ public static function retry(callable $decider, callable $delay = null)
169
+ {
170
+ return function (callable $handler) use ($decider, $delay) {
171
+ return new RetryMiddleware($decider, $handler, $delay);
172
+ };
173
+ }
174
+
175
+ /**
176
+ * Middleware that logs requests, responses, and errors using a message
177
+ * formatter.
178
+ *
179
+ * @param LoggerInterface $logger Logs messages.
180
+ * @param MessageFormatter $formatter Formatter used to create message strings.
181
+ * @param string $logLevel Level at which to log requests.
182
+ *
183
+ * @return callable Returns a function that accepts the next handler.
184
+ */
185
+ public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = LogLevel::INFO)
186
+ {
187
+ return function (callable $handler) use ($logger, $formatter, $logLevel) {
188
+ return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
189
+ return $handler($request, $options)->then(
190
+ function ($response) use ($logger, $request, $formatter, $logLevel) {
191
+ $message = $formatter->format($request, $response);
192
+ $logger->log($logLevel, $message);
193
+ return $response;
194
+ },
195
+ function ($reason) use ($logger, $request, $formatter) {
196
+ $response = $reason instanceof RequestException
197
+ ? $reason->getResponse()
198
+ : null;
199
+ $message = $formatter->format($request, $response, $reason);
200
+ $logger->notice($message);
201
+ return \GuzzleHttp\Promise\rejection_for($reason);
202
+ }
203
+ );
204
+ };
205
+ };
206
+ }
207
+
208
+ /**
209
+ * This middleware adds a default content-type if possible, a default
210
+ * content-length or transfer-encoding header, and the expect header.
211
+ *
212
+ * @return callable
213
+ */
214
+ public static function prepareBody()
215
+ {
216
+ return function (callable $handler) {
217
+ return new PrepareBodyMiddleware($handler);
218
+ };
219
+ }
220
+
221
+ /**
222
+ * Middleware that applies a map function to the request before passing to
223
+ * the next handler.
224
+ *
225
+ * @param callable $fn Function that accepts a RequestInterface and returns
226
+ * a RequestInterface.
227
+ * @return callable
228
+ */
229
+ public static function mapRequest(callable $fn)
230
+ {
231
+ return function (callable $handler) use ($fn) {
232
+ return function ($request, array $options) use ($handler, $fn) {
233
+ return $handler($fn($request), $options);
234
+ };
235
+ };
236
+ }
237
+
238
+ /**
239
+ * Middleware that applies a map function to the resolved promise's
240
+ * response.
241
+ *
242
+ * @param callable $fn Function that accepts a ResponseInterface and
243
+ * returns a ResponseInterface.
244
+ * @return callable
245
+ */
246
+ public static function mapResponse(callable $fn)
247
+ {
248
+ return function (callable $handler) use ($fn) {
249
+ return function ($request, array $options) use ($handler, $fn) {
250
+ return $handler($request, $options)->then($fn);
251
+ };
252
+ };
253
+ }
254
+ }
lib/Azure/GuzzleHttp/Pool.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Promise\PromisorInterface;
5
+ use Psr\Http\Message\RequestInterface;
6
+ use GuzzleHttp\Promise\EachPromise;
7
+
8
+ /**
9
+ * Sends and iterator of requests concurrently using a capped pool size.
10
+ *
11
+ * The pool will read from an iterator until it is cancelled or until the
12
+ * iterator is consumed. When a request is yielded, the request is sent after
13
+ * applying the "request_options" request options (if provided in the ctor).
14
+ *
15
+ * When a function is yielded by the iterator, the function is provided the
16
+ * "request_options" array that should be merged on top of any existing
17
+ * options, and the function MUST then return a wait-able promise.
18
+ */
19
+ class Pool implements PromisorInterface
20
+ {
21
+ /** @var EachPromise */
22
+ private $each;
23
+
24
+ /**
25
+ * @param ClientInterface $client Client used to send the requests.
26
+ * @param array|\Iterator $requests Requests or functions that return
27
+ * requests to send concurrently.
28
+ * @param array $config Associative array of options
29
+ * - concurrency: (int) Maximum number of requests to send concurrently
30
+ * - options: Array of request options to apply to each request.
31
+ * - fulfilled: (callable) Function to invoke when a request completes.
32
+ * - rejected: (callable) Function to invoke when a request is rejected.
33
+ */
34
+ public function __construct(
35
+ ClientInterface $client,
36
+ $requests,
37
+ array $config = []
38
+ ) {
39
+ // Backwards compatibility.
40
+ if (isset($config['pool_size'])) {
41
+ $config['concurrency'] = $config['pool_size'];
42
+ } elseif (!isset($config['concurrency'])) {
43
+ $config['concurrency'] = 25;
44
+ }
45
+
46
+ if (isset($config['options'])) {
47
+ $opts = $config['options'];
48
+ unset($config['options']);
49
+ } else {
50
+ $opts = [];
51
+ }
52
+
53
+ $iterable = \GuzzleHttp\Promise\iter_for($requests);
54
+ $requests = function () use ($iterable, $client, $opts) {
55
+ foreach ($iterable as $key => $rfn) {
56
+ if ($rfn instanceof RequestInterface) {
57
+ yield $key => $client->sendAsync($rfn, $opts);
58
+ } elseif (is_callable($rfn)) {
59
+ yield $key => $rfn($opts);
60
+ } else {
61
+ throw new \InvalidArgumentException('Each value yielded by '
62
+ . 'the iterator must be a Psr7\Http\Message\RequestInterface '
63
+ . 'or a callable that returns a promise that fulfills '
64
+ . 'with a Psr7\Message\Http\ResponseInterface object.');
65
+ }
66
+ }
67
+ };
68
+
69
+ $this->each = new EachPromise($requests(), $config);
70
+ }
71
+
72
+ public function promise()
73
+ {
74
+ return $this->each->promise();
75
+ }
76
+
77
+ /**
78
+ * Sends multiple requests concurrently and returns an array of responses
79
+ * and exceptions that uses the same ordering as the provided requests.
80
+ *
81
+ * IMPORTANT: This method keeps every request and response in memory, and
82
+ * as such, is NOT recommended when sending a large number or an
83
+ * indeterminate number of requests concurrently.
84
+ *
85
+ * @param ClientInterface $client Client used to send the requests
86
+ * @param array|\Iterator $requests Requests to send concurrently.
87
+ * @param array $options Passes through the options available in
88
+ * {@see GuzzleHttp\Pool::__construct}
89
+ *
90
+ * @return array Returns an array containing the response or an exception
91
+ * in the same order that the requests were sent.
92
+ * @throws \InvalidArgumentException if the event format is incorrect.
93
+ */
94
+ public static function batch(
95
+ ClientInterface $client,
96
+ $requests,
97
+ array $options = []
98
+ ) {
99
+ $res = [];
100
+ self::cmpCallback($options, 'fulfilled', $res);
101
+ self::cmpCallback($options, 'rejected', $res);
102
+ $pool = new static($client, $requests, $options);
103
+ $pool->promise()->wait();
104
+ ksort($res);
105
+
106
+ return $res;
107
+ }
108
+
109
+ private static function cmpCallback(array &$options, $name, array &$results)
110
+ {
111
+ if (!isset($options[$name])) {
112
+ $options[$name] = function ($v, $k) use (&$results) {
113
+ $results[$k] = $v;
114
+ };
115
+ } else {
116
+ $currentFn = $options[$name];
117
+ $options[$name] = function ($v, $k) use (&$results, $currentFn) {
118
+ $currentFn($v, $k);
119
+ $results[$k] = $v;
120
+ };
121
+ }
122
+ }
123
+ }
lib/Azure/GuzzleHttp/PrepareBodyMiddleware.php ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Promise\PromiseInterface;
5
+ use GuzzleHttp\Psr7;
6
+ use Psr\Http\Message\RequestInterface;
7
+
8
+ /**
9
+ * Prepares requests that contain a body, adding the Content-Length,
10
+ * Content-Type, and Expect headers.
11
+ */
12
+ class PrepareBodyMiddleware
13
+ {
14
+ /** @var callable */
15
+ private $nextHandler;
16
+
17
+ /** @var array */
18
+ private static $skipMethods = ['GET' => true, 'HEAD' => true];
19
+
20
+ /**
21
+ * @param callable $nextHandler Next handler to invoke.
22
+ */
23
+ public function __construct(callable $nextHandler)
24
+ {
25
+ $this->nextHandler = $nextHandler;
26
+ }
27
+
28
+ /**
29
+ * @param RequestInterface $request
30
+ * @param array $options
31
+ *
32
+ * @return PromiseInterface
33
+ */
34
+ public function __invoke(RequestInterface $request, array $options)
35
+ {
36
+ $fn = $this->nextHandler;
37
+
38
+ // Don't do anything if the request has no body.
39
+ if (isset(self::$skipMethods[$request->getMethod()])
40
+ || $request->getBody()->getSize() === 0
41
+ ) {
42
+ return $fn($request, $options);
43
+ }
44
+
45
+ $modify = [];
46
+
47
+ // Add a default content-type if possible.
48
+ if (!$request->hasHeader('Content-Type')) {
49
+ if ($uri = $request->getBody()->getMetadata('uri')) {
50
+ if ($type = Psr7\mimetype_from_filename($uri)) {
51
+ $modify['set_headers']['Content-Type'] = $type;
52
+ }
53
+ }
54
+ }
55
+
56
+ // Add a default content-length or transfer-encoding header.
57
+ if (!isset(self::$skipMethods[$request->getMethod()])
58
+ && !$request->hasHeader('Content-Length')
59
+ && !$request->hasHeader('Transfer-Encoding')
60
+ ) {
61
+ $size = $request->getBody()->getSize();
62
+ if ($size !== null) {
63
+ $modify['set_headers']['Content-Length'] = $size;
64
+ } else {
65
+ $modify['set_headers']['Transfer-Encoding'] = 'chunked';
66
+ }
67
+ }
68
+
69
+ // Add the expect header if needed.
70
+ $this->addExpectHeader($request, $options, $modify);
71
+
72
+ return $fn(Psr7\modify_request($request, $modify), $options);
73
+ }
74
+
75
+ private function addExpectHeader(
76
+ RequestInterface $request,
77
+ array $options,
78
+ array &$modify
79
+ ) {
80
+ // Determine if the Expect header should be used
81
+ if ($request->hasHeader('Expect')) {
82
+ return;
83
+ }
84
+
85
+ $expect = isset($options['expect']) ? $options['expect'] : null;
86
+
87
+ // Return if disabled or if you're not using HTTP/1.1 or HTTP/2.0
88
+ if ($expect === false || $request->getProtocolVersion() < 1.1) {
89
+ return;
90
+ }
91
+
92
+ // The expect header is unconditionally enabled
93
+ if ($expect === true) {
94
+ $modify['set_headers']['Expect'] = '100-Continue';
95
+ return;
96
+ }
97
+
98
+ // By default, send the expect header when the payload is > 1mb
99
+ if ($expect === null) {
100
+ $expect = 1048576;
101
+ }
102
+
103
+ // Always add if the body cannot be rewound, the size cannot be
104
+ // determined, or the size is greater than the cutoff threshold
105
+ $body = $request->getBody();
106
+ $size = $body->getSize();
107
+
108
+ if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
109
+ $modify['set_headers']['Expect'] = '100-Continue';
110
+ }
111
+ }
112
+ }
lib/Azure/GuzzleHttp/Promise/AggregateException.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * Exception thrown when too many errors occur in the some() or any() methods.
6
+ */
7
+ class AggregateException extends RejectionException
8
+ {
9
+ public function __construct($msg, array $reasons)
10
+ {
11
+ parent::__construct(
12
+ $reasons,
13
+ sprintf('%s; %d rejected promises', $msg, count($reasons))
14
+ );
15
+ }
16
+ }
lib/Azure/GuzzleHttp/Promise/CancellationException.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * Exception that is set as the reason for a promise that has been cancelled.
6
+ */
7
+ class CancellationException extends RejectionException
8
+ {
9
+ }
lib/Azure/GuzzleHttp/Promise/Coroutine.php ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ use Exception;
5
+ use Generator;
6
+ use Throwable;
7
+
8
+ /**
9
+ * Creates a promise that is resolved using a generator that yields values or
10
+ * promises (somewhat similar to C#'s async keyword).
11
+ *
12
+ * When called, the coroutine function will start an instance of the generator
13
+ * and returns a promise that is fulfilled with its final yielded value.
14
+ *
15
+ * Control is returned back to the generator when the yielded promise settles.
16
+ * This can lead to less verbose code when doing lots of sequential async calls
17
+ * with minimal processing in between.
18
+ *
19
+ * use GuzzleHttp\Promise;
20
+ *
21
+ * function createPromise($value) {
22
+ * return new Promise\FulfilledPromise($value);
23
+ * }
24
+ *
25
+ * $promise = Promise\coroutine(function () {
26
+ * $value = (yield createPromise('a'));
27
+ * try {
28
+ * $value = (yield createPromise($value . 'b'));
29
+ * } catch (\Exception $e) {
30
+ * // The promise was rejected.
31
+ * }
32
+ * yield $value . 'c';
33
+ * });
34
+ *
35
+ * // Outputs "abc"
36
+ * $promise->then(function ($v) { echo $v; });
37
+ *
38
+ * @param callable $generatorFn Generator function to wrap into a promise.
39
+ *
40
+ * @return Promise
41
+ * @link https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
42
+ */
43
+ final class Coroutine implements PromiseInterface
44
+ {
45
+ /**
46
+ * @var PromiseInterface|null
47
+ */
48
+ private $currentPromise;
49
+
50
+ /**
51
+ * @var Generator
52
+ */
53
+ private $generator;
54
+
55
+ /**
56
+ * @var Promise
57
+ */
58
+ private $result;
59
+
60
+ public function __construct(callable $generatorFn)
61
+ {
62
+ $this->generator = $generatorFn();
63
+ $this->result = new Promise(function () {
64
+ while (isset($this->currentPromise)) {
65
+ $this->currentPromise->wait();
66
+ }
67
+ });
68
+ $this->nextCoroutine($this->generator->current());
69
+ }
70
+
71
+ public function then(
72
+ callable $onFulfilled = null,
73
+ callable $onRejected = null
74
+ ) {
75
+ return $this->result->then($onFulfilled, $onRejected);
76
+ }
77
+
78
+ public function otherwise(callable $onRejected)
79
+ {
80
+ return $this->result->otherwise($onRejected);
81
+ }
82
+
83
+ public function wait($unwrap = true)
84
+ {
85
+ return $this->result->wait($unwrap);
86
+ }
87
+
88
+ public function getState()
89
+ {
90
+ return $this->result->getState();
91
+ }
92
+
93
+ public function resolve($value)
94
+ {
95
+ $this->result->resolve($value);
96
+ }
97
+
98
+ public function reject($reason)
99
+ {
100
+ $this->result->reject($reason);
101
+ }
102
+
103
+ public function cancel()
104
+ {
105
+ $this->currentPromise->cancel();
106
+ $this->result->cancel();
107
+ }
108
+
109
+ private function nextCoroutine($yielded)
110
+ {
111
+ $this->currentPromise = promise_for($yielded)
112
+ ->then([$this, '_handleSuccess'], [$this, '_handleFailure']);
113
+ }
114
+
115
+ /**
116
+ * @internal
117
+ */
118
+ public function _handleSuccess($value)
119
+ {
120
+ unset($this->currentPromise);
121
+ try {
122
+ $next = $this->generator->send($value);
123
+ if ($this->generator->valid()) {
124
+ $this->nextCoroutine($next);
125
+ } else {
126
+ $this->result->resolve($value);
127
+ }
128
+ } catch (Exception $exception) {
129
+ $this->result->reject($exception);
130
+ } catch (Throwable $throwable) {
131
+ $this->result->reject($throwable);
132
+ }
133
+ }
134
+
135
+ /**
136
+ * @internal
137
+ */
138
+ public function _handleFailure($reason)
139
+ {
140
+ unset($this->currentPromise);
141
+ try {
142
+ $nextYield = $this->generator->throw(exception_for($reason));
143
+ // The throw was caught, so keep iterating on the coroutine
144
+ $this->nextCoroutine($nextYield);
145
+ } catch (Exception $exception) {
146
+ $this->result->reject($exception);
147
+ } catch (Throwable $throwable) {
148
+ $this->result->reject($throwable);
149
+ }
150
+ }
151
+ }
lib/Azure/GuzzleHttp/Promise/EachPromise.php ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * Represents a promise that iterates over many promises and invokes
6
+ * side-effect functions in the process.
7
+ */
8
+ class EachPromise implements PromisorInterface
9
+ {
10
+ private $pending = [];
11
+
12
+ /** @var \Iterator */
13
+ private $iterable;
14
+
15
+ /** @var callable|int */
16
+ private $concurrency;
17
+
18
+ /** @var callable */
19
+ private $onFulfilled;
20
+
21
+ /** @var callable */
22
+ private $onRejected;
23
+
24
+ /** @var Promise */
25
+ private $aggregate;
26
+
27
+ /** @var bool */
28
+ private $mutex;
29
+
30
+ /**
31
+ * Configuration hash can include the following key value pairs:
32
+ *
33
+ * - fulfilled: (callable) Invoked when a promise fulfills. The function
34
+ * is invoked with three arguments: the fulfillment value, the index
35
+ * position from the iterable list of the promise, and the aggregate
36
+ * promise that manages all of the promises. The aggregate promise may
37
+ * be resolved from within the callback to short-circuit the promise.
38
+ * - rejected: (callable) Invoked when a promise is rejected. The
39
+ * function is invoked with three arguments: the rejection reason, the
40
+ * index position from the iterable list of the promise, and the
41
+ * aggregate promise that manages all of the promises. The aggregate
42
+ * promise may be resolved from within the callback to short-circuit
43
+ * the promise.
44
+ * - concurrency: (integer) Pass this configuration option to limit the
45
+ * allowed number of outstanding concurrently executing promises,
46
+ * creating a capped pool of promises. There is no limit by default.
47
+ *
48
+ * @param mixed $iterable Promises or values to iterate.
49
+ * @param array $config Configuration options
50
+ */
51
+ public function __construct($iterable, array $config = [])
52
+ {
53
+ $this->iterable = iter_for($iterable);
54
+
55
+ if (isset($config['concurrency'])) {
56
+ $this->concurrency = $config['concurrency'];
57
+ }
58
+
59
+ if (isset($config['fulfilled'])) {
60
+ $this->onFulfilled = $config['fulfilled'];
61
+ }
62
+
63
+ if (isset($config['rejected'])) {
64
+ $this->onRejected = $config['rejected'];
65
+ }
66
+ }
67
+
68
+ public function promise()
69
+ {
70
+ if ($this->aggregate) {
71
+ return $this->aggregate;
72
+ }
73
+
74
+ try {
75
+ $this->createPromise();
76
+ $this->iterable->rewind();
77
+ $this->refillPending();
78
+ } catch (\Throwable $e) {
79
+ $this->aggregate->reject($e);
80
+ } catch (\Exception $e) {
81
+ $this->aggregate->reject($e);
82
+ }
83
+
84
+ return $this->aggregate;
85
+ }
86
+
87
+ private function createPromise()
88
+ {
89
+ $this->mutex = false;
90
+ $this->aggregate = new Promise(function () {
91
+ reset($this->pending);
92
+ if (empty($this->pending) && !$this->iterable->valid()) {
93
+ $this->aggregate->resolve(null);
94
+ return;
95
+ }
96
+
97
+ // Consume a potentially fluctuating list of promises while
98
+ // ensuring that indexes are maintained (precluding array_shift).
99
+ while ($promise = current($this->pending)) {
100
+ next($this->pending);
101
+ $promise->wait();
102
+ if ($this->aggregate->getState() !== PromiseInterface::PENDING) {
103
+ return;
104
+ }
105
+ }
106
+ });
107
+
108
+ // Clear the references when the promise is resolved.
109
+ $clearFn = function () {
110
+ $this->iterable = $this->concurrency = $this->pending = null;
111
+ $this->onFulfilled = $this->onRejected = null;
112
+ };
113
+
114
+ $this->aggregate->then($clearFn, $clearFn);
115
+ }
116
+
117
+ private function refillPending()
118
+ {
119
+ if (!$this->concurrency) {
120
+ // Add all pending promises.
121
+ while ($this->addPending() && $this->advanceIterator());
122
+ return;
123
+ }
124
+
125
+ // Add only up to N pending promises.
126
+ $concurrency = is_callable($this->concurrency)
127
+ ? call_user_func($this->concurrency, count($this->pending))
128
+ : $this->concurrency;
129
+ $concurrency = max($concurrency - count($this->pending), 0);
130
+ // Concurrency may be set to 0 to disallow new promises.
131
+ if (!$concurrency) {
132
+ return;
133
+ }
134
+ // Add the first pending promise.
135
+ $this->addPending();
136
+ // Note this is special handling for concurrency=1 so that we do
137
+ // not advance the iterator after adding the first promise. This
138
+ // helps work around issues with generators that might not have the
139
+ // next value to yield until promise callbacks are called.
140
+ while (--$concurrency
141
+ && $this->advanceIterator()
142
+ && $this->addPending());
143
+ }
144
+
145
+ private function addPending()
146
+ {
147
+ if (!$this->iterable || !$this->iterable->valid()) {
148
+ return false;
149
+ }
150
+
151
+ $promise = promise_for($this->iterable->current());
152
+ $idx = $this->iterable->key();
153
+
154
+ $this->pending[$idx] = $promise->then(
155
+ function ($value) use ($idx) {
156
+ if ($this->onFulfilled) {
157
+ call_user_func(
158
+ $this->onFulfilled, $value, $idx, $this->aggregate
159
+ );
160
+ }
161
+ $this->step($idx);
162
+ },
163
+ function ($reason) use ($idx) {
164
+ if ($this->onRejected) {
165
+ call_user_func(
166
+ $this->onRejected, $reason, $idx, $this->aggregate
167
+ );
168
+ }
169
+ $this->step($idx);
170
+ }
171
+ );
172
+
173
+ return true;
174
+ }
175
+
176
+ private function advanceIterator()
177
+ {
178
+ // Place a lock on the iterator so that we ensure to not recurse,
179
+ // preventing fatal generator errors.
180
+ if ($this->mutex) {
181
+ return false;
182
+ }
183
+
184
+ $this->mutex = true;
185
+
186
+ try {
187
+ $this->iterable->next();
188
+ $this->mutex = false;
189
+ return true;
190
+ } catch (\Throwable $e) {
191
+ $this->aggregate->reject($e);
192
+ $this->mutex = false;
193
+ return false;
194
+ } catch (\Exception $e) {
195
+ $this->aggregate->reject($e);
196
+ $this->mutex = false;
197
+ return false;
198
+ }
199
+ }
200
+
201
+ private function step($idx)
202
+ {
203
+ // If the promise was already resolved, then ignore this step.
204
+ if ($this->aggregate->getState() !== PromiseInterface::PENDING) {
205
+ return;
206
+ }
207
+
208
+ unset($this->pending[$idx]);
209
+
210
+ // Only refill pending promises if we are not locked, preventing the
211
+ // EachPromise to recursively invoke the provided iterator, which
212
+ // cause a fatal error: "Cannot resume an already running generator"
213
+ if ($this->advanceIterator() && !$this->checkIfFinished()) {
214
+ // Add more pending promises if possible.
215
+ $this->refillPending();
216
+ }
217
+ }
218
+
219
+ private function checkIfFinished()
220
+ {
221
+ if (!$this->pending && !$this->iterable->valid()) {
222
+ // Resolve the promise if there's nothing left to do.
223
+ $this->aggregate->resolve(null);
224
+ return true;
225
+ }
226
+
227
+ return false;
228
+ }
229
+ }
lib/Azure/GuzzleHttp/Promise/FulfilledPromise.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * A promise that has been fulfilled.
6
+ *
7
+ * Thenning off of this promise will invoke the onFulfilled callback
8
+ * immediately and ignore other callbacks.
9
+ */
10
+ class FulfilledPromise implements PromiseInterface
11
+ {
12
+ private $value;
13
+
14
+ public function __construct($value)
15
+ {
16
+ if (method_exists($value, 'then')) {
17
+ throw new \InvalidArgumentException(
18
+ 'You cannot create a FulfilledPromise with a promise.');
19
+ }
20
+
21
+ $this->value = $value;
22
+ }
23
+
24
+ public function then(
25
+ callable $onFulfilled = null,
26
+ callable $onRejected = null
27
+ ) {
28
+ // Return itself if there is no onFulfilled function.
29
+ if (!$onFulfilled) {
30
+ return $this;
31
+ }
32
+
33
+ $queue = queue();
34
+ $p = new Promise([$queue, 'run']);
35
+ $value = $this->value;
36
+ $queue->add(static function () use ($p, $value, $onFulfilled) {
37
+ if ($p->getState() === self::PENDING) {
38
+ try {
39
+ $p->resolve($onFulfilled($value));
40
+ } catch (\Throwable $e) {
41
+ $p->reject($e);
42
+ } catch (\Exception $e) {
43
+ $p->reject($e);
44
+ }
45
+ }
46
+ });
47
+
48
+ return $p;
49
+ }
50
+
51
+ public function otherwise(callable $onRejected)
52
+ {
53
+ return $this->then(null, $onRejected);
54
+ }
55
+
56
+ public function wait($unwrap = true, $defaultDelivery = null)
57
+ {
58
+ return $unwrap ? $this->value : null;
59
+ }
60
+
61
+ public function getState()
62
+ {
63
+ return self::FULFILLED;
64
+ }
65
+
66
+ public function resolve($value)
67
+ {
68
+ if ($value !== $this->value) {
69
+ throw new \LogicException("Cannot resolve a fulfilled promise");
70
+ }
71
+ }
72
+
73
+ public function reject($reason)
74
+ {
75
+ throw new \LogicException("Cannot reject a fulfilled promise");
76
+ }
77
+
78
+ public function cancel()
79
+ {
80
+ // pass
81
+ }
82
+ }
lib/Azure/GuzzleHttp/Promise/Promise.php ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * Promises/A+ implementation that avoids recursion when possible.
6
+ *
7
+ * @link https://promisesaplus.com/
8
+ */
9
+ class Promise implements PromiseInterface
10
+ {
11
+ private $state = self::PENDING;
12
+ private $result;
13
+ private $cancelFn;
14
+ private $waitFn;
15
+ private $waitList;
16
+ private $handlers = [];
17
+
18
+ /**
19
+ * @param callable $waitFn Fn that when invoked resolves the promise.
20
+ * @param callable $cancelFn Fn that when invoked cancels the promise.
21
+ */
22
+ public function __construct(
23
+ callable $waitFn = null,
24
+ callable $cancelFn = null
25
+ ) {
26
+ $this->waitFn = $waitFn;
27
+ $this->cancelFn = $cancelFn;
28
+ }
29
+
30
+ public function then(
31
+ callable $onFulfilled = null,
32
+ callable $onRejected = null
33
+ ) {
34
+ if ($this->state === self::PENDING) {
35
+ $p = new Promise(null, [$this, 'cancel']);
36
+ $this->handlers[] = [$p, $onFulfilled, $onRejected];
37
+ $p->waitList = $this->waitList;
38
+ $p->waitList[] = $this;
39
+ return $p;
40
+ }
41
+
42
+ // Return a fulfilled promise and immediately invoke any callbacks.
43
+ if ($this->state === self::FULFILLED) {
44
+ return $onFulfilled
45
+ ? promise_for($this->result)->then($onFulfilled)
46
+ : promise_for($this->result);
47
+ }
48
+
49
+ // It's either cancelled or rejected, so return a rejected promise
50
+ // and immediately invoke any callbacks.
51
+ $rejection = rejection_for($this->result);
52
+ return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
53
+ }
54
+
55
+ public function otherwise(callable $onRejected)
56
+ {
57
+ return $this->then(null, $onRejected);
58
+ }
59
+
60
+ public function wait($unwrap = true)
61
+ {
62
+ $this->waitIfPending();
63
+
64
+ $inner = $this->result instanceof PromiseInterface
65
+ ? $this->result->wait($unwrap)
66
+ : $this->result;
67
+
68
+ if ($unwrap) {
69
+ if ($this->result instanceof PromiseInterface
70
+ || $this->state === self::FULFILLED
71
+ ) {
72
+ return $inner;
73
+ } else {
74
+ // It's rejected so "unwrap" and throw an exception.
75
+ throw exception_for($inner);
76
+ }
77
+ }
78
+ }
79
+
80
+ public function getState()
81
+ {
82
+ return $this->state;
83
+ }
84
+
85
+ public function cancel()
86
+ {
87
+ if ($this->state !== self::PENDING) {
88
+ return;
89
+ }
90
+
91
+ $this->waitFn = $this->waitList = null;
92
+
93
+ if ($this->cancelFn) {
94
+ $fn = $this->cancelFn;
95
+ $this->cancelFn = null;
96
+ try {
97
+ $fn();
98
+ } catch (\Throwable $e) {
99
+ $this->reject($e);
100
+ } catch (\Exception $e) {
101
+ $this->reject($e);
102
+ }
103
+ }
104
+
105
+ // Reject the promise only if it wasn't rejected in a then callback.
106
+ if ($this->state === self::PENDING) {
107
+ $this->reject(new CancellationException('Promise has been cancelled'));
108
+ }
109
+ }
110
+
111
+ public function resolve($value)
112
+ {
113
+ $this->settle(self::FULFILLED, $value);
114
+ }
115
+
116
+ public function reject($reason)
117
+ {
118
+ $this->settle(self::REJECTED, $reason);
119
+ }
120
+
121
+ private function settle($state, $value)
122
+ {
123
+ if ($this->state !== self::PENDING) {
124
+ // Ignore calls with the same resolution.
125
+ if ($state === $this->state && $value === $this->result) {
126
+ return;
127
+ }
128
+ throw $this->state === $state
129
+ ? new \LogicException("The promise is already {$state}.")
130
+ : new \LogicException("Cannot change a {$this->state} promise to {$state}");
131
+ }
132
+
133
+ if ($value === $this) {
134
+ throw new \LogicException('Cannot fulfill or reject a promise with itself');
135
+ }
136
+
137
+ // Clear out the state of the promise but stash the handlers.
138
+ $this->state = $state;
139
+ $this->result = $value;
140
+ $handlers = $this->handlers;
141
+ $this->handlers = null;
142
+ $this->waitList = $this->waitFn = null;
143
+ $this->cancelFn = null;
144
+
145
+ if (!$handlers) {
146
+ return;
147
+ }
148
+
149
+ // If the value was not a settled promise or a thenable, then resolve
150
+ // it in the task queue using the correct ID.
151
+ if (!method_exists($value, 'then')) {
152
+ $id = $state === self::FULFILLED ? 1 : 2;
153
+ // It's a success, so resolve the handlers in the queue.
154
+ queue()->add(static function () use ($id, $value, $handlers) {
155
+ foreach ($handlers as $handler) {
156
+ self::callHandler($id, $value, $handler);
157
+ }
158
+ });
159
+ } elseif ($value instanceof Promise
160
+ && $value->getState() === self::PENDING
161
+ ) {
162
+ // We can just merge our handlers onto the next promise.
163
+ $value->handlers = array_merge($value->handlers, $handlers);
164
+ } else {
165
+ // Resolve the handlers when the forwarded promise is resolved.
166
+ $value->then(
167
+ static function ($value) use ($handlers) {
168
+ foreach ($handlers as $handler) {
169
+ self::callHandler(1, $value, $handler);
170
+ }
171
+ },
172
+ static function ($reason) use ($handlers) {
173
+ foreach ($handlers as $handler) {
174
+ self::callHandler(2, $reason, $handler);
175
+ }
176
+ }
177
+ );
178
+ }
179
+ }
180
+
181
+ /**
182
+ * Call a stack of handlers using a specific callback index and value.
183
+ *
184
+ * @param int $index 1 (resolve) or 2 (reject).
185
+ * @param mixed $value Value to pass to the callback.
186
+ * @param array $handler Array of handler data (promise and callbacks).
187
+ *
188
+ * @return array Returns the next group to resolve.
189
+ */
190
+ private static function callHandler($index, $value, array $handler)
191
+ {
192
+ /** @var PromiseInterface $promise */
193
+ $promise = $handler[0];
194
+
195
+ // The promise may have been cancelled or resolved before placing
196
+ // this thunk in the queue.
197
+ if ($promise->getState() !== self::PENDING) {
198
+ return;
199
+ }
200
+
201
+ try {
202
+ if (isset($handler[$index])) {
203
+ $promise->resolve($handler[$index]($value));
204
+ } elseif ($index === 1) {
205
+ // Forward resolution values as-is.
206
+ $promise->resolve($value);
207
+ } else {
208
+ // Forward rejections down the chain.
209
+ $promise->reject($value);
210
+ }
211
+ } catch (\Throwable $reason) {
212
+ $promise->reject($reason);
213
+ } catch (\Exception $reason) {
214
+ $promise->reject($reason);
215
+ }
216
+ }
217
+
218
+ private function waitIfPending()
219
+ {
220
+ if ($this->state !== self::PENDING) {
221
+ return;
222
+ } elseif ($this->waitFn) {
223
+ $this->invokeWaitFn();
224
+ } elseif ($this->waitList) {
225
+ $this->invokeWaitList();
226
+ } else {
227
+ // If there's not wait function, then reject the promise.
228
+ $this->reject('Cannot wait on a promise that has '
229
+ . 'no internal wait function. You must provide a wait '
230
+ . 'function when constructing the promise to be able to '
231
+ . 'wait on a promise.');
232
+ }
233
+
234
+ queue()->run();
235
+
236
+ if ($this->state === self::PENDING) {
237
+ $this->reject('Invoking the wait callback did not resolve the promise');
238
+ }
239
+ }
240
+
241
+ private function invokeWaitFn()
242
+ {
243
+ try {
244
+ $wfn = $this->waitFn;
245
+ $this->waitFn = null;
246
+ $wfn(true);
247
+ } catch (\Exception $reason) {
248
+ if ($this->state === self::PENDING) {
249
+ // The promise has not been resolved yet, so reject the promise
250
+ // with the exception.
251
+ $this->reject($reason);
252
+ } else {
253
+ // The promise was already resolved, so there's a problem in
254
+ // the application.
255
+ throw $reason;
256
+ }
257
+ }
258
+ }
259
+
260
+ private function invokeWaitList()
261
+ {
262
+ $waitList = $this->waitList;
263
+ $this->waitList = null;
264
+
265
+ foreach ($waitList as $result) {
266
+ $result->waitIfPending();
267
+ while ($result->result instanceof Promise) {
268
+ $result = $result->result;
269
+ $result->waitIfPending();
270
+ }
271
+ }
272
+ }
273
+ }
lib/Azure/GuzzleHttp/Promise/PromiseInterface.php ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * A promise represents the eventual result of an asynchronous operation.
6
+ *
7
+ * The primary way of interacting with a promise is through its then method,
8
+ * which registers callbacks to receive either a promise’s eventual value or
9
+ * the reason why the promise cannot be fulfilled.
10
+ *
11
+ * @link https://promisesaplus.com/
12
+ */
13
+ interface PromiseInterface
14
+ {
15
+ const PENDING = 'pending';
16
+ const FULFILLED = 'fulfilled';
17
+ const REJECTED = 'rejected';
18
+
19
+ /**
20
+ * Appends fulfillment and rejection handlers to the promise, and returns
21
+ * a new promise resolving to the return value of the called handler.
22
+ *
23
+ * @param callable $onFulfilled Invoked when the promise fulfills.
24
+ * @param callable $onRejected Invoked when the promise is rejected.
25
+ *
26
+ * @return PromiseInterface
27
+ */
28
+ public function then(
29
+ callable $onFulfilled = null,
30
+ callable $onRejected = null
31
+ );
32
+
33
+ /**
34
+ * Appends a rejection handler callback to the promise, and returns a new
35
+ * promise resolving to the return value of the callback if it is called,
36
+ * or to its original fulfillment value if the promise is instead
37
+ * fulfilled.
38
+ *
39
+ * @param callable $onRejected Invoked when the promise is rejected.
40
+ *
41
+ * @return PromiseInterface
42
+ */
43
+ public function otherwise(callable $onRejected);
44
+
45
+ /**
46
+ * Get the state of the promise ("pending", "rejected", or "fulfilled").
47
+ *
48
+ * The three states can be checked against the constants defined on
49
+ * PromiseInterface: PENDING, FULFILLED, and REJECTED.
50
+ *
51
+ * @return string
52
+ */
53
+ public function getState();
54
+
55
+ /**
56
+ * Resolve the promise with the given value.
57
+ *
58
+ * @param mixed $value
59
+ * @throws \RuntimeException if the promise is already resolved.
60
+ */
61
+ public function resolve($value);
62
+
63
+ /**
64
+ * Reject the promise with the given reason.
65
+ *
66
+ * @param mixed $reason
67
+ * @throws \RuntimeException if the promise is already resolved.
68
+ */
69
+ public function reject($reason);
70
+
71
+ /**
72
+ * Cancels the promise if possible.
73
+ *
74
+ * @link https://github.com/promises-aplus/cancellation-spec/issues/7
75
+ */
76
+ public function cancel();
77
+
78
+ /**
79
+ * Waits until the promise completes if possible.
80
+ *
81
+ * Pass $unwrap as true to unwrap the result of the promise, either
82
+ * returning the resolved value or throwing the rejected exception.
83
+ *
84
+ * If the promise cannot be waited on, then the promise will be rejected.
85
+ *
86
+ * @param bool $unwrap
87
+ *
88
+ * @return mixed
89
+ * @throws \LogicException if the promise has no wait function or if the
90
+ * promise does not settle after waiting.
91
+ */
92
+ public function wait($unwrap = true);
93
+ }
lib/Azure/GuzzleHttp/Promise/PromisorInterface.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * Interface used with classes that return a promise.
6
+ */
7
+ interface PromisorInterface
8
+ {
9
+ /**
10
+ * Returns a promise.
11
+ *
12
+ * @return PromiseInterface
13
+ */
14
+ public function promise();
15
+ }
lib/Azure/GuzzleHttp/Promise/RejectedPromise.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * A promise that has been rejected.
6
+ *
7
+ * Thenning off of this promise will invoke the onRejected callback
8
+ * immediately and ignore other callbacks.
9
+ */
10
+ class RejectedPromise implements PromiseInterface
11
+ {
12
+ private $reason;
13
+
14
+ public function __construct($reason)
15
+ {
16
+ if (method_exists($reason, 'then')) {
17
+ throw new \InvalidArgumentException(
18
+ 'You cannot create a RejectedPromise with a promise.');
19
+ }
20
+
21
+ $this->reason = $reason;
22
+ }
23
+
24
+ public function then(
25
+ callable $onFulfilled = null,
26
+ callable $onRejected = null
27
+ ) {
28
+ // If there's no onRejected callback then just return self.
29
+ if (!$onRejected) {
30
+ return $this;
31
+ }
32
+
33
+ $queue = queue();
34
+ $reason = $this->reason;
35
+ $p = new Promise([$queue, 'run']);
36
+ $queue->add(static function () use ($p, $reason, $onRejected) {
37
+ if ($p->getState() === self::PENDING) {
38
+ try {
39
+ // Return a resolved promise if onRejected does not throw.
40
+ $p->resolve($onRejected($reason));
41
+ } catch (\Throwable $e) {
42
+ // onRejected threw, so return a rejected promise.
43
+ $p->reject($e);
44
+ } catch (\Exception $e) {
45
+ // onRejected threw, so return a rejected promise.
46
+ $p->reject($e);
47
+ }
48
+ }
49
+ });
50
+
51
+ return $p;
52
+ }
53
+
54
+ public function otherwise(callable $onRejected)
55
+ {
56
+ return $this->then(null, $onRejected);
57
+ }
58
+
59
+ public function wait($unwrap = true, $defaultDelivery = null)
60
+ {
61
+ if ($unwrap) {
62
+ throw exception_for($this->reason);
63
+ }
64
+ }
65
+
66
+ public function getState()
67
+ {
68
+ return self::REJECTED;
69
+ }
70
+
71
+ public function resolve($value)
72
+ {
73
+ throw new \LogicException("Cannot resolve a rejected promise");
74
+ }
75
+
76
+ public function reject($reason)
77
+ {
78
+ if ($reason !== $this->reason) {
79
+ throw new \LogicException("Cannot reject a rejected promise");
80
+ }
81
+ }
82
+
83
+ public function cancel()
84
+ {
85
+ // pass
86
+ }
87
+ }
lib/Azure/GuzzleHttp/Promise/RejectionException.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * A special exception that is thrown when waiting on a rejected promise.
6
+ *
7
+ * The reason value is available via the getReason() method.
8
+ */
9
+ class RejectionException extends \RuntimeException
10
+ {
11
+ /** @var mixed Rejection reason. */
12
+ private $reason;
13
+
14
+ /**
15
+ * @param mixed $reason Rejection reason.
16
+ * @param string $description Optional description
17
+ */
18
+ public function __construct($reason, $description = null)
19
+ {
20
+ $this->reason = $reason;
21
+
22
+ $message = 'The promise was rejected';
23
+
24
+ if ($description) {
25
+ $message .= ' with reason: ' . $description;
26
+ } elseif (is_string($reason)
27
+ || (is_object($reason) && method_exists($reason, '__toString'))
28
+ ) {
29
+ $message .= ' with reason: ' . $this->reason;
30
+ } elseif ($reason instanceof \JsonSerializable) {
31
+ $message .= ' with reason: '
32
+ . json_encode($this->reason, JSON_PRETTY_PRINT);
33
+ }
34
+
35
+ parent::__construct($message);
36
+ }
37
+
38
+ /**
39
+ * Returns the rejection reason.
40
+ *
41
+ * @return mixed
42
+ */
43
+ public function getReason()
44
+ {
45
+ return $this->reason;
46
+ }
47
+ }
lib/Azure/GuzzleHttp/Promise/TaskQueue.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * A task queue that executes tasks in a FIFO order.
6
+ *
7
+ * This task queue class is used to settle promises asynchronously and
8
+ * maintains a constant stack size. You can use the task queue asynchronously
9
+ * by calling the `run()` function of the global task queue in an event loop.
10
+ *
11
+ * GuzzleHttp\Promise\queue()->run();
12
+ */
13
+ class TaskQueue implements TaskQueueInterface
14
+ {
15
+ private $enableShutdown = true;
16
+ private $queue = [];
17
+
18
+ public function __construct($withShutdown = true)
19
+ {
20
+ if ($withShutdown) {
21
+ register_shutdown_function(function () {
22
+ if ($this->enableShutdown) {
23
+ // Only run the tasks if an E_ERROR didn't occur.
24
+ $err = error_get_last();
25
+ if (!$err || ($err['type'] ^ E_ERROR)) {
26
+ $this->run();
27
+ }
28
+ }
29
+ });
30
+ }
31
+ }
32
+
33
+ public function isEmpty()
34
+ {
35
+ return !$this->queue;
36
+ }
37
+
38
+ public function add(callable $task)
39
+ {
40
+ $this->queue[] = $task;
41
+ }
42
+
43
+ public function run()
44
+ {
45
+ /** @var callable $task */
46
+ while ($task = array_shift($this->queue)) {
47
+ $task();
48
+ }
49
+ }
50
+
51
+ /**
52
+ * The task queue will be run and exhausted by default when the process
53
+ * exits IFF the exit is not the result of a PHP E_ERROR error.
54
+ *
55
+ * You can disable running the automatic shutdown of the queue by calling
56
+ * this function. If you disable the task queue shutdown process, then you
57
+ * MUST either run the task queue (as a result of running your event loop
58
+ * or manually using the run() method) or wait on each outstanding promise.
59
+ *
60
+ * Note: This shutdown will occur before any destructors are triggered.
61
+ */
62
+ public function disableShutdown()
63
+ {
64
+ $this->enableShutdown = false;
65
+ }
66
+ }
lib/Azure/GuzzleHttp/Promise/TaskQueueInterface.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ interface TaskQueueInterface
5
+ {
6
+ /**
7
+ * Returns true if the queue is empty.
8
+ *
9
+ * @return bool
10
+ */
11
+ public function isEmpty();
12
+
13
+ /**
14
+ * Adds a task to the queue that will be executed the next time run is
15
+ * called.
16
+ *
17
+ * @param callable $task
18
+ */
19
+ public function add(callable $task);
20
+
21
+ /**
22
+ * Execute all of the pending task in the queue.
23
+ */
24
+ public function run();
25
+ }
lib/Azure/GuzzleHttp/Promise/functions.php ADDED
@@ -0,0 +1,457 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Promise;
3
+
4
+ /**
5
+ * Get the global task queue used for promise resolution.
6
+ *
7
+ * This task queue MUST be run in an event loop in order for promises to be
8
+ * settled asynchronously. It will be automatically run when synchronously
9
+ * waiting on a promise.
10
+ *
11
+ * <code>
12
+ * while ($eventLoop->isRunning()) {
13
+ * GuzzleHttp\Promise\queue()->run();
14
+ * }
15
+ * </code>
16
+ *
17
+ * @param TaskQueueInterface $assign Optionally specify a new queue instance.
18
+ *
19
+ * @return TaskQueueInterface
20
+ */
21
+ function queue(TaskQueueInterface $assign = null)
22
+ {
23
+ static $queue;
24
+
25
+ if ($assign) {
26
+ $queue = $assign;
27
+ } elseif (!$queue) {
28
+ $queue = new TaskQueue();
29
+ }
30
+
31
+ return $queue;
32
+ }
33
+
34
+ /**
35
+ * Adds a function to run in the task queue when it is next `run()` and returns
36
+ * a promise that is fulfilled or rejected with the result.
37
+ *
38
+ * @param callable $task Task function to run.
39
+ *
40
+ * @return PromiseInterface
41
+ */
42
+ function task(callable $task)
43
+ {
44
+ $queue = queue();
45
+ $promise = new Promise([$queue, 'run']);
46
+ $queue->add(function () use ($task, $promise) {
47
+ try {
48
+ $promise->resolve($task());
49
+ } catch (\Throwable $e) {
50
+ $promise->reject($e);
51
+ } catch (\Exception $e) {
52
+ $promise->reject($e);
53
+ }
54
+ });
55
+
56
+ return $promise;
57
+ }
58
+
59
+ /**
60
+ * Creates a promise for a value if the value is not a promise.
61
+ *
62
+ * @param mixed $value Promise or value.
63
+ *
64
+ * @return PromiseInterface
65
+ */
66
+ function promise_for($value)
67
+ {
68
+ if ($value instanceof PromiseInterface) {
69
+ return $value;
70
+ }
71
+
72
+ // Return a Guzzle promise that shadows the given promise.
73
+ if (method_exists($value, 'then')) {
74
+ $wfn = method_exists($value, 'wait') ? [$value, 'wait'] : null;
75
+ $cfn = method_exists($value, 'cancel') ? [$value, 'cancel'] : null;
76
+ $promise = new Promise($wfn, $cfn);
77
+ $value->then([$promise, 'resolve'], [$promise, 'reject']);
78
+ return $promise;
79
+ }
80
+
81
+ return new FulfilledPromise($value);
82
+ }
83
+
84
+ /**
85
+ * Creates a rejected promise for a reason if the reason is not a promise. If
86
+ * the provided reason is a promise, then it is returned as-is.
87
+ *
88
+ * @param mixed $reason Promise or reason.
89
+ *
90
+ * @return PromiseInterface
91
+ */
92
+ function rejection_for($reason)
93
+ {
94
+ if ($reason instanceof PromiseInterface) {
95
+ return $reason;
96
+ }
97
+
98
+ return new RejectedPromise($reason);
99
+ }
100
+
101
+ /**
102
+ * Create an exception for a rejected promise value.
103
+ *
104
+ * @param mixed $reason
105
+ *
106
+ * @return \Exception|\Throwable
107
+ */
108
+ function exception_for($reason)
109
+ {
110
+ return $reason instanceof \Exception || $reason instanceof \Throwable
111
+ ? $reason
112
+ : new RejectionException($reason);
113
+ }
114
+
115
+ /**
116
+ * Returns an iterator for the given value.
117
+ *
118
+ * @param mixed $value
119
+ *
120
+ * @return \Iterator
121
+ */
122
+ function iter_for($value)
123
+ {
124
+ if ($value instanceof \Iterator) {
125
+ return $value;
126
+ } elseif (is_array($value)) {
127
+ return new \ArrayIterator($value);
128
+ } else {
129
+ return new \ArrayIterator([$value]);
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Synchronously waits on a promise to resolve and returns an inspection state
135
+ * array.
136
+ *
137
+ * Returns a state associative array containing a "state" key mapping to a
138
+ * valid promise state. If the state of the promise is "fulfilled", the array
139
+ * will contain a "value" key mapping to the fulfilled value of the promise. If
140
+ * the promise is rejected, the array will contain a "reason" key mapping to
141
+ * the rejection reason of the promise.
142
+ *
143
+ * @param PromiseInterface $promise Promise or value.
144
+ *
145
+ * @return array
146
+ */
147
+ function inspect(PromiseInterface $promise)
148
+ {
149
+ try {
150
+ return [
151
+ 'state' => PromiseInterface::FULFILLED,
152
+ 'value' => $promise->wait()
153
+ ];
154
+ } catch (RejectionException $e) {
155
+ return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()];
156
+ } catch (\Throwable $e) {
157
+ return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
158
+ } catch (\Exception $e) {
159
+ return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Waits on all of the provided promises, but does not unwrap rejected promises
165
+ * as thrown exception.
166
+ *
167
+ * Returns an array of inspection state arrays.
168
+ *
169
+ * @param PromiseInterface[] $promises Traversable of promises to wait upon.
170
+ *
171
+ * @return array
172
+ * @see GuzzleHttp\Promise\inspect for the inspection state array format.
173
+ */
174
+ function inspect_all($promises)
175
+ {
176
+ $results = [];
177
+ foreach ($promises as $key => $promise) {
178
+ $results[$key] = inspect($promise);
179
+ }
180
+
181
+ return $results;
182
+ }
183
+
184
+ /**
185
+ * Waits on all of the provided promises and returns the fulfilled values.
186
+ *
187
+ * Returns an array that contains the value of each promise (in the same order
188
+ * the promises were provided). An exception is thrown if any of the promises
189
+ * are rejected.
190
+ *
191
+ * @param mixed $promises Iterable of PromiseInterface objects to wait on.
192
+ *
193
+ * @return array
194
+ * @throws \Exception on error
195
+ * @throws \Throwable on error in PHP >=7
196
+ */
197
+ function unwrap($promises)
198
+ {
199
+ $results = [];
200
+ foreach ($promises as $key => $promise) {
201
+ $results[$key] = $promise->wait();
202
+ }
203
+
204
+ return $results;
205
+ }
206
+
207
+ /**
208
+ * Given an array of promises, return a promise that is fulfilled when all the
209
+ * items in the array are fulfilled.
210
+ *
211
+ * The promise's fulfillment value is an array with fulfillment values at
212
+ * respective positions to the original array. If any promise in the array
213
+ * rejects, the returned promise is rejected with the rejection reason.
214
+ *
215
+ * @param mixed $promises Promises or values.
216
+ *
217
+ * @return PromiseInterface
218
+ */
219
+ function all($promises)
220
+ {
221
+ $results = [];
222
+ return each(
223
+ $promises,
224
+ function ($value, $idx) use (&$results) {
225
+ $results[$idx] = $value;
226
+ },
227
+ function ($reason, $idx, Promise $aggregate) {
228
+ $aggregate->reject($reason);
229
+ }
230
+ )->then(function () use (&$results) {
231
+ ksort($results);
232
+ return $results;
233
+ });
234
+ }
235
+
236
+ /**
237
+ * Initiate a competitive race between multiple promises or values (values will
238
+ * become immediately fulfilled promises).
239
+ *
240
+ * When count amount of promises have been fulfilled, the returned promise is
241
+ * fulfilled with an array that contains the fulfillment values of the winners
242
+ * in order of resolution.
243
+ *
244
+ * This prommise is rejected with a {@see GuzzleHttp\Promise\AggregateException}
245
+ * if the number of fulfilled promises is less than the desired $count.
246
+ *
247
+ * @param int $count Total number of promises.
248
+ * @param mixed $promises Promises or values.
249
+ *
250
+ * @return PromiseInterface
251
+ */
252
+ function some($count, $promises)
253
+ {
254
+ $results = [];
255
+ $rejections = [];
256
+
257
+ return each(
258
+ $promises,
259
+ function ($value, $idx, PromiseInterface $p) use (&$results, $count) {
260
+ if ($p->getState() !== PromiseInterface::PENDING) {
261
+ return;
262
+ }
263
+ $results[$idx] = $value;
264
+ if (count($results) >= $count) {
265
+ $p->resolve(null);
266
+ }
267
+ },
268
+ function ($reason) use (&$rejections) {
269
+ $rejections[] = $reason;
270
+ }
271
+ )->then(
272
+ function () use (&$results, &$rejections, $count) {
273
+ if (count($results) !== $count) {
274
+ throw new AggregateException(
275
+ 'Not enough promises to fulfill count',
276
+ $rejections
277
+ );
278
+ }
279
+ ksort($results);
280
+ return array_values($results);
281
+ }
282
+ );
283
+ }
284
+
285
+ /**
286
+ * Like some(), with 1 as count. However, if the promise fulfills, the
287
+ * fulfillment value is not an array of 1 but the value directly.
288
+ *
289
+ * @param mixed $promises Promises or values.
290
+ *
291
+ * @return PromiseInterface
292
+ */
293
+ function any($promises)
294
+ {
295
+ return some(1, $promises)->then(function ($values) { return $values[0]; });
296
+ }
297
+
298
+ /**
299
+ * Returns a promise that is fulfilled when all of the provided promises have
300
+ * been fulfilled or rejected.
301
+ *
302
+ * The returned promise is fulfilled with an array of inspection state arrays.
303
+ *
304
+ * @param mixed $promises Promises or values.
305
+ *
306
+ * @return PromiseInterface
307
+ * @see GuzzleHttp\Promise\inspect for the inspection state array format.
308
+ */
309
+ function settle($promises)
310
+ {
311
+ $results = [];
312
+
313
+ return each(
314
+ $promises,
315
+ function ($value, $idx) use (&$results) {
316
+ $results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value];
317
+ },
318
+ function ($reason, $idx) use (&$results) {
319
+ $results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason];
320
+ }
321
+ )->then(function () use (&$results) {
322
+ ksort($results);
323
+ return $results;
324
+ });
325
+ }
326
+
327
+ /**
328
+ * Given an iterator that yields promises or values, returns a promise that is
329
+ * fulfilled with a null value when the iterator has been consumed or the
330
+ * aggregate promise has been fulfilled or rejected.
331
+ *
332
+ * $onFulfilled is a function that accepts the fulfilled value, iterator
333
+ * index, and the aggregate promise. The callback can invoke any necessary side
334
+ * effects and choose to resolve or reject the aggregate promise if needed.
335
+ *
336
+ * $onRejected is a function that accepts the rejection reason, iterator
337
+ * index, and the aggregate promise. The callback can invoke any necessary side
338
+ * effects and choose to resolve or reject the aggregate promise if needed.
339
+ *
340
+ * @param mixed $iterable Iterator or array to iterate over.
341
+ * @param callable $onFulfilled
342
+ * @param callable $onRejected
343
+ *
344
+ * @return PromiseInterface
345
+ */
346
+ function each(
347
+ $iterable,
348
+ callable $onFulfilled = null,
349
+ callable $onRejected = null
350
+ ) {
351
+ return (new EachPromise($iterable, [
352
+ 'fulfilled' => $onFulfilled,
353
+ 'rejected' => $onRejected
354
+ ]))->promise();
355
+ }
356
+
357
+ /**
358
+ * Like each, but only allows a certain number of outstanding promises at any
359
+ * given time.
360
+ *
361
+ * $concurrency may be an integer or a function that accepts the number of
362
+ * pending promises and returns a numeric concurrency limit value to allow for
363
+ * dynamic a concurrency size.
364
+ *
365
+ * @param mixed $iterable
366
+ * @param int|callable $concurrency
367
+ * @param callable $onFulfilled
368
+ * @param callable $onRejected
369
+ *
370
+ * @return PromiseInterface
371
+ */
372
+ function each_limit(
373
+ $iterable,
374
+ $concurrency,
375
+ callable $onFulfilled = null,
376
+ callable $onRejected = null
377
+ ) {
378
+ return (new EachPromise($iterable, [
379
+ 'fulfilled' => $onFulfilled,
380
+ 'rejected' => $onRejected,
381
+ 'concurrency' => $concurrency
382
+ ]))->promise();
383
+ }
384
+
385
+ /**
386
+ * Like each_limit, but ensures that no promise in the given $iterable argument
387
+ * is rejected. If any promise is rejected, then the aggregate promise is
388
+ * rejected with the encountered rejection.
389
+ *
390
+ * @param mixed $iterable
391
+ * @param int|callable $concurrency
392
+ * @param callable $onFulfilled
393
+ *
394
+ * @return PromiseInterface
395
+ */
396
+ function each_limit_all(
397
+ $iterable,
398
+ $concurrency,
399
+ callable $onFulfilled = null
400
+ ) {
401
+ return each_limit(
402
+ $iterable,
403
+ $concurrency,
404
+ $onFulfilled,
405
+ function ($reason, $idx, PromiseInterface $aggregate) {
406
+ $aggregate->reject($reason);
407
+ }
408
+ );
409
+ }
410
+
411
+ /**
412
+ * Returns true if a promise is fulfilled.
413
+ *
414
+ * @param PromiseInterface $promise
415
+ *
416
+ * @return bool
417
+ */
418
+ function is_fulfilled(PromiseInterface $promise)
419
+ {
420
+ return $promise->getState() === PromiseInterface::FULFILLED;
421
+ }
422
+
423
+ /**
424
+ * Returns true if a promise is rejected.
425
+ *
426
+ * @param PromiseInterface $promise
427
+ *
428
+ * @return bool
429
+ */
430
+ function is_rejected(PromiseInterface $promise)
431
+ {
432
+ return $promise->getState() === PromiseInterface::REJECTED;
433
+ }
434
+
435
+ /**
436
+ * Returns true if a promise is fulfilled or rejected.
437
+ *
438
+ * @param PromiseInterface $promise
439
+ *
440
+ * @return bool
441
+ */
442
+ function is_settled(PromiseInterface $promise)
443
+ {
444
+ return $promise->getState() !== PromiseInterface::PENDING;
445
+ }
446
+
447
+ /**
448
+ * @see Coroutine
449
+ *
450
+ * @param callable $generatorFn
451
+ *
452
+ * @return PromiseInterface
453
+ */
454
+ function coroutine(callable $generatorFn)
455
+ {
456
+ return new Coroutine($generatorFn);
457
+ }
lib/Azure/GuzzleHttp/Promise/functions_include.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Don't redefine the functions if included multiple times.
4
+ if (!function_exists('GuzzleHttp\Promise\promise_for')) {
5
+ require __DIR__ . '/functions.php';
6
+ }
lib/Azure/GuzzleHttp/Psr7/AppendStream.php ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Reads from multiple streams, one after the other.
8
+ *
9
+ * This is a read-only stream decorator.
10
+ */
11
+ class AppendStream implements StreamInterface
12
+ {
13
+ /** @var StreamInterface[] Streams being decorated */
14
+ private $streams = [];
15
+
16
+ private $seekable = true;
17
+ private $current = 0;
18
+ private $pos = 0;
19
+ private $detached = false;
20
+
21
+ /**
22
+ * @param StreamInterface[] $streams Streams to decorate. Each stream must
23
+ * be readable.
24
+ */
25
+ public function __construct(array $streams = [])
26
+ {
27
+ foreach ($streams as $stream) {
28
+ $this->addStream($stream);
29
+ }
30
+ }
31
+
32
+ public function __toString()
33
+ {
34
+ try {
35
+ $this->rewind();
36
+ return $this->getContents();
37
+ } catch (\Exception $e) {
38
+ return '';
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Add a stream to the AppendStream
44
+ *
45
+ * @param StreamInterface $stream Stream to append. Must be readable.
46
+ *
47
+ * @throws \InvalidArgumentException if the stream is not readable
48
+ */
49
+ public function addStream(StreamInterface $stream)
50
+ {
51
+ if (!$stream->isReadable()) {
52
+ throw new \InvalidArgumentException('Each stream must be readable');
53
+ }
54
+
55
+ // The stream is only seekable if all streams are seekable
56
+ if (!$stream->isSeekable()) {
57
+ $this->seekable = false;
58
+ }
59
+
60
+ $this->streams[] = $stream;
61
+ }
62
+
63
+ public function getContents()
64
+ {
65
+ return copy_to_string($this);
66
+ }
67
+
68
+ /**
69
+ * Closes each attached stream.
70
+ *
71
+ * {@inheritdoc}
72
+ */
73
+ public function close()
74
+ {
75
+ $this->pos = $this->current = 0;
76
+
77
+ foreach ($this->streams as $stream) {
78
+ $stream->close();
79
+ }
80
+
81
+ $this->streams = [];
82
+ }
83
+
84
+ /**
85
+ * Detaches each attached stream
86
+ *
87
+ * {@inheritdoc}
88
+ */
89
+ public function detach()
90
+ {
91
+ $this->close();
92
+ $this->detached = true;
93
+ }
94
+
95
+ public function tell()
96
+ {
97
+ return $this->pos;
98
+ }
99
+
100
+ /**
101
+ * Tries to calculate the size by adding the size of each stream.
102
+ *
103
+ * If any of the streams do not return a valid number, then the size of the
104
+ * append stream cannot be determined and null is returned.
105
+ *
106
+ * {@inheritdoc}
107
+ */
108
+ public function getSize()
109
+ {
110
+ $size = 0;
111
+
112
+ foreach ($this->streams as $stream) {
113
+ $s = $stream->getSize();
114
+ if ($s === null) {
115
+ return null;
116
+ }
117
+ $size += $s;
118
+ }
119
+
120
+ return $size;
121
+ }
122
+
123
+ public function eof()
124
+ {
125
+ return !$this->streams ||
126
+ ($this->current >= count($this->streams) - 1 &&
127
+ $this->streams[$this->current]->eof());
128
+ }
129
+
130
+ public function rewind()
131
+ {
132
+ $this->seek(0);
133
+ }
134
+
135
+ /**
136
+ * Attempts to seek to the given position. Only supports SEEK_SET.
137
+ *
138
+ * {@inheritdoc}
139
+ */
140
+ public function seek($offset, $whence = SEEK_SET)
141
+ {
142
+ if (!$this->seekable) {
143
+ throw new \RuntimeException('This AppendStream is not seekable');
144
+ } elseif ($whence !== SEEK_SET) {
145
+ throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');
146
+ }
147
+
148
+ $this->pos = $this->current = 0;
149
+
150
+ // Rewind each stream
151
+ foreach ($this->streams as $i => $stream) {
152
+ try {
153
+ $stream->rewind();
154
+ } catch (\Exception $e) {
155
+ throw new \RuntimeException('Unable to seek stream '
156
+ . $i . ' of the AppendStream', 0, $e);
157
+ }
158
+ }
159
+
160
+ // Seek to the actual position by reading from each stream
161
+ while ($this->pos < $offset && !$this->eof()) {
162
+ $result = $this->read(min(8096, $offset - $this->pos));
163
+ if ($result === '') {
164
+ break;
165
+ }
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Reads from all of the appended streams until the length is met or EOF.
171
+ *
172
+ * {@inheritdoc}
173
+ */
174
+ public function read($length)
175
+ {
176
+ $buffer = '';
177
+ $total = count($this->streams) - 1;
178
+ $remaining = $length;
179
+ $progressToNext = false;
180
+
181
+ while ($remaining > 0) {
182
+
183
+ // Progress to the next stream if needed.
184
+ if ($progressToNext || $this->streams[$this->current]->eof()) {
185
+ $progressToNext = false;
186
+ if ($this->current === $total) {
187
+ break;
188
+ }
189
+ $this->current++;
190
+ }
191
+
192
+ $result = $this->streams[$this->current]->read($remaining);
193
+
194
+ // Using a loose comparison here to match on '', false, and null
195
+ if ($result == null) {
196
+ $progressToNext = true;
197
+ continue;
198
+ }
199
+
200
+ $buffer .= $result;
201
+ $remaining = $length - strlen($buffer);
202
+ }
203
+
204
+ $this->pos += strlen($buffer);
205
+
206
+ return $buffer;
207
+ }
208
+
209
+ public function isReadable()
210
+ {
211
+ return true;
212
+ }
213
+
214
+ public function isWritable()
215
+ {
216
+ return false;
217
+ }
218
+
219
+ public function isSeekable()
220
+ {
221
+ return $this->seekable;
222
+ }
223
+
224
+ public function write($string)
225
+ {
226
+ throw new \RuntimeException('Cannot write to an AppendStream');
227
+ }
228
+
229
+ public function getMetadata($key = null)
230
+ {
231
+ return $key ? null : [];
232
+ }
233
+ }
lib/Azure/GuzzleHttp/Psr7/BufferStream.php ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Provides a buffer stream that can be written to to fill a buffer, and read
8
+ * from to remove bytes from the buffer.
9
+ *
10
+ * This stream returns a "hwm" metadata value that tells upstream consumers
11
+ * what the configured high water mark of the stream is, or the maximum
12
+ * preferred size of the buffer.
13
+ */
14
+ class BufferStream implements StreamInterface
15
+ {
16
+ private $hwm;
17
+ private $buffer = '';
18
+
19
+ /**
20
+ * @param int $hwm High water mark, representing the preferred maximum
21
+ * buffer size. If the size of the buffer exceeds the high
22
+ * water mark, then calls to write will continue to succeed
23
+ * but will return false to inform writers to slow down
24
+ * until the buffer has been drained by reading from it.
25
+ */
26
+ public function __construct($hwm = 16384)
27
+ {
28
+ $this->hwm = $hwm;
29
+ }
30
+
31
+ public function __toString()
32
+ {
33
+ return $this->getContents();
34
+ }
35
+
36
+ public function getContents()
37
+ {
38
+ $buffer = $this->buffer;
39
+ $this->buffer = '';
40
+
41
+ return $buffer;
42
+ }
43
+
44
+ public function close()
45
+ {
46
+ $this->buffer = '';
47
+ }
48
+
49
+ public function detach()
50
+ {
51
+ $this->close();
52
+ }
53
+
54
+ public function getSize()
55
+ {
56
+ return strlen($this->buffer);
57
+ }
58
+
59
+ public function isReadable()
60
+ {
61
+ return true;
62
+ }
63
+
64
+ public function isWritable()
65
+ {
66
+ return true;
67
+ }
68
+
69
+ public function isSeekable()
70
+ {
71
+ return false;
72
+ }
73
+
74
+ public function rewind()
75
+ {
76
+ $this->seek(0);
77
+ }
78
+
79
+ public function seek($offset, $whence = SEEK_SET)
80
+ {
81
+ throw new \RuntimeException('Cannot seek a BufferStream');
82
+ }
83
+
84
+ public function eof()
85
+ {
86
+ return strlen($this->buffer) === 0;
87
+ }
88
+
89
+ public function tell()
90
+ {
91
+ throw new \RuntimeException('Cannot determine the position of a BufferStream');
92
+ }
93
+
94
+ /**
95
+ * Reads data from the buffer.
96
+ */
97
+ public function read($length)
98
+ {
99
+ $currentLength = strlen($this->buffer);
100
+
101
+ if ($length >= $currentLength) {
102
+ // No need to slice the buffer because we don't have enough data.
103
+ $result = $this->buffer;
104
+ $this->buffer = '';
105
+ } else {
106
+ // Slice up the result to provide a subset of the buffer.
107
+ $result = substr($this->buffer, 0, $length);
108
+ $this->buffer = substr($this->buffer, $length);
109
+ }
110
+
111
+ return $result;
112
+ }
113
+
114
+ /**
115
+ * Writes data to the buffer.
116
+ */
117
+ public function write($string)
118
+ {
119
+ $this->buffer .= $string;
120
+
121
+ // TODO: What should happen here?
122
+ if (strlen($this->buffer) >= $this->hwm) {
123
+ return false;
124
+ }
125
+
126
+ return strlen($string);
127
+ }
128
+
129
+ public function getMetadata($key = null)
130
+ {
131
+ if ($key == 'hwm') {
132
+ return $this->hwm;
133
+ }
134
+
135
+ return $key ? null : [];
136
+ }
137
+ }
lib/Azure/GuzzleHttp/Psr7/CachingStream.php ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Stream decorator that can cache previously read bytes from a sequentially
8
+ * read stream.
9
+ */
10
+ class CachingStream implements StreamInterface
11
+ {
12
+ use StreamDecoratorTrait;
13
+
14
+ /** @var StreamInterface Stream being wrapped */
15
+ private $remoteStream;
16
+
17
+ /** @var int Number of bytes to skip reading due to a write on the buffer */
18
+ private $skipReadBytes = 0;
19
+
20
+ /**
21
+ * We will treat the buffer object as the body of the stream
22
+ *
23
+ * @param StreamInterface $stream Stream to cache
24
+ * @param StreamInterface $target Optionally specify where data is cached
25
+ */
26
+ public function __construct(
27
+ StreamInterface $stream,
28
+ StreamInterface $target = null
29
+ ) {
30
+ $this->remoteStream = $stream;
31
+ $this->stream = $target ?: new Stream(fopen('php://temp', 'r+'));
32
+ }
33
+
34
+ public function getSize()
35
+ {
36
+ return max($this->stream->getSize(), $this->remoteStream->getSize());
37
+ }
38
+
39
+ public function rewind()
40
+ {
41
+ $this->seek(0);
42
+ }
43
+
44
+ public function seek($offset, $whence = SEEK_SET)
45
+ {
46
+ if ($whence == SEEK_SET) {
47
+ $byte = $offset;
48
+ } elseif ($whence == SEEK_CUR) {
49
+ $byte = $offset + $this->tell();
50
+ } elseif ($whence == SEEK_END) {
51
+ $size = $this->remoteStream->getSize();
52
+ if ($size === null) {
53
+ $size = $this->cacheEntireStream();
54
+ }
55
+ $byte = $size + $offset;
56
+ } else {
57
+ throw new \InvalidArgumentException('Invalid whence');
58
+ }
59
+
60
+ $diff = $byte - $this->stream->getSize();
61
+
62
+ if ($diff > 0) {
63
+ // Read the remoteStream until we have read in at least the amount
64
+ // of bytes requested, or we reach the end of the file.
65
+ while ($diff > 0 && !$this->remoteStream->eof()) {
66
+ $this->read($diff);
67
+ $diff = $byte - $this->stream->getSize();
68
+ }
69
+ } else {
70
+ // We can just do a normal seek since we've already seen this byte.
71
+ $this->stream->seek($byte);
72
+ }
73
+ }
74
+
75
+ public function read($length)
76
+ {
77
+ // Perform a regular read on any previously read data from the buffer
78
+ $data = $this->stream->read($length);
79
+ $remaining = $length - strlen($data);
80
+
81
+ // More data was requested so read from the remote stream
82
+ if ($remaining) {
83
+ // If data was written to the buffer in a position that would have
84
+ // been filled from the remote stream, then we must skip bytes on
85
+ // the remote stream to emulate overwriting bytes from that
86
+ // position. This mimics the behavior of other PHP stream wrappers.
87
+ $remoteData = $this->remoteStream->read(
88
+ $remaining + $this->skipReadBytes
89
+ );
90
+
91
+ if ($this->skipReadBytes) {
92
+ $len = strlen($remoteData);
93
+ $remoteData = substr($remoteData, $this->skipReadBytes);
94
+ $this->skipReadBytes = max(0, $this->skipReadBytes - $len);
95
+ }
96
+
97
+ $data .= $remoteData;
98
+ $this->stream->write($remoteData);
99
+ }
100
+
101
+ return $data;
102
+ }
103
+
104
+ public function write($string)
105
+ {
106
+ // When appending to the end of the currently read stream, you'll want
107
+ // to skip bytes from being read from the remote stream to emulate
108
+ // other stream wrappers. Basically replacing bytes of data of a fixed
109
+ // length.
110
+ $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell();
111
+ if ($overflow > 0) {
112
+ $this->skipReadBytes += $overflow;
113
+ }
114
+
115
+ return $this->stream->write($string);
116
+ }
117
+
118
+ public function eof()
119
+ {
120
+ return $this->stream->eof() && $this->remoteStream->eof();
121
+ }
122
+
123
+ /**
124
+ * Close both the remote stream and buffer stream
125
+ */
126
+ public function close()
127
+ {
128
+ $this->remoteStream->close() && $this->stream->close();
129
+ }
130
+
131
+ private function cacheEntireStream()
132
+ {
133
+ $target = new FnStream(['write' => 'strlen']);
134
+ copy_to_stream($this, $target);
135
+
136
+ return $this->tell();
137
+ }
138
+ }
lib/Azure/GuzzleHttp/Psr7/DroppingStream.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Stream decorator that begins dropping data once the size of the underlying
8
+ * stream becomes too full.
9
+ */
10
+ class DroppingStream implements StreamInterface
11
+ {
12
+ use StreamDecoratorTrait;
13
+
14
+ private $maxLength;
15
+
16
+ /**
17
+ * @param StreamInterface $stream Underlying stream to decorate.
18
+ * @param int $maxLength Maximum size before dropping data.
19
+ */
20
+ public function __construct(StreamInterface $stream, $maxLength)
21
+ {
22
+ $this->stream = $stream;
23
+ $this->maxLength = $maxLength;
24
+ }
25
+
26
+ public function write($string)
27
+ {
28
+ $diff = $this->maxLength - $this->stream->getSize();
29
+
30
+ // Begin returning 0 when the underlying stream is too large.
31
+ if ($diff <= 0) {
32
+ return 0;
33
+ }
34
+
35
+ // Write the stream or a subset of the stream if needed.
36
+ if (strlen($string) < $diff) {
37
+ return $this->stream->write($string);
38
+ }
39
+
40
+ return $this->stream->write(substr($string, 0, $diff));
41
+ }
42
+ }
lib/Azure/GuzzleHttp/Psr7/FnStream.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Compose stream implementations based on a hash of functions.
8
+ *
9
+ * Allows for easy testing and extension of a provided stream without needing
10
+ * to create a concrete class for a simple extension point.
11
+ */
12
+ class FnStream implements StreamInterface
13
+ {
14
+ /** @var array */
15
+ private $methods;
16
+
17
+ /** @var array Methods that must be implemented in the given array */
18
+ private static $slots = ['__toString', 'close', 'detach', 'rewind',
19
+ 'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',
20
+ 'isReadable', 'read', 'getContents', 'getMetadata'];
21
+
22
+ /**
23
+ * @param array $methods Hash of method name to a callable.
24
+ */
25
+ public function __construct(array $methods)
26
+ {
27
+ $this->methods = $methods;
28
+
29
+ // Create the functions on the class
30
+ foreach ($methods as $name => $fn) {
31
+ $this->{'_fn_' . $name} = $fn;
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Lazily determine which methods are not implemented.
37
+ * @throws \BadMethodCallException
38
+ */
39
+ public function __get($name)
40
+ {
41
+ throw new \BadMethodCallException(str_replace('_fn_', '', $name)
42
+ . '() is not implemented in the FnStream');
43
+ }
44
+
45
+ /**
46
+ * The close method is called on the underlying stream only if possible.
47
+ */
48
+ public function __destruct()
49
+ {
50
+ if (isset($this->_fn_close)) {
51
+ call_user_func($this->_fn_close);
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Adds custom functionality to an underlying stream by intercepting
57
+ * specific method calls.
58
+ *
59
+ * @param StreamInterface $stream Stream to decorate
60
+ * @param array $methods Hash of method name to a closure
61
+ *
62
+ * @return FnStream
63
+ */
64
+ public static function decorate(StreamInterface $stream, array $methods)
65
+ {
66
+ // If any of the required methods were not provided, then simply
67
+ // proxy to the decorated stream.
68
+ foreach (array_diff(self::$slots, array_keys($methods)) as $diff) {
69
+ $methods[$diff] = [$stream, $diff];
70
+ }
71
+
72
+ return new self($methods);
73
+ }
74
+
75
+ public function __toString()
76
+ {
77
+ return call_user_func($this->_fn___toString);
78
+ }
79
+
80
+ public function close()
81
+ {
82
+ return call_user_func($this->_fn_close);
83
+ }
84
+
85
+ public function detach()
86
+ {
87
+ return call_user_func($this->_fn_detach);
88
+ }
89
+
90
+ public function getSize()
91
+ {
92
+ return call_user_func($this->_fn_getSize);
93
+ }
94
+
95
+ public function tell()
96
+ {
97
+ return call_user_func($this->_fn_tell);
98
+ }
99
+
100
+ public function eof()
101
+ {
102
+ return call_user_func($this->_fn_eof);
103
+ }
104
+
105
+ public function isSeekable()
106
+ {
107
+ return call_user_func($this->_fn_isSeekable);
108
+ }
109
+
110
+ public function rewind()
111
+ {
112
+ call_user_func($this->_fn_rewind);
113
+ }
114
+
115
+ public function seek($offset, $whence = SEEK_SET)
116
+ {
117
+ call_user_func($this->_fn_seek, $offset, $whence);
118
+ }
119
+
120
+ public function isWritable()
121
+ {
122
+ return call_user_func($this->_fn_isWritable);
123
+ }
124
+
125
+ public function write($string)
126
+ {
127
+ return call_user_func($this->_fn_write, $string);
128
+ }
129
+
130
+ public function isReadable()
131
+ {
132
+ return call_user_func($this->_fn_isReadable);
133
+ }
134
+
135
+ public function read($length)
136
+ {
137
+ return call_user_func($this->_fn_read, $length);
138
+ }
139
+
140
+ public function getContents()
141
+ {
142
+ return call_user_func($this->_fn_getContents);
143
+ }
144
+
145
+ public function getMetadata($key = null)
146
+ {
147
+ return call_user_func($this->_fn_getMetadata, $key);
148
+ }
149
+ }
lib/Azure/GuzzleHttp/Psr7/InflateStream.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Uses PHP's zlib.inflate filter to inflate deflate or gzipped content.
8
+ *
9
+ * This stream decorator skips the first 10 bytes of the given stream to remove
10
+ * the gzip header, converts the provided stream to a PHP stream resource,
11
+ * then appends the zlib.inflate filter. The stream is then converted back
12
+ * to a Guzzle stream resource to be used as a Guzzle stream.
13
+ *
14
+ * @link http://tools.ietf.org/html/rfc1952
15
+ * @link http://php.net/manual/en/filters.compression.php
16
+ */
17
+ class InflateStream implements StreamInterface
18
+ {
19
+ use StreamDecoratorTrait;
20
+
21
+ public function __construct(StreamInterface $stream)
22
+ {
23
+ // read the first 10 bytes, ie. gzip header
24
+ $header = $stream->read(10);
25
+ $filenameHeaderLength = $this->getLengthOfPossibleFilenameHeader($stream, $header);
26
+ // Skip the header, that is 10 + length of filename + 1 (nil) bytes
27
+ $stream = new LimitStream($stream, -1, 10 + $filenameHeaderLength);
28
+ $resource = StreamWrapper::getResource($stream);
29
+ stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ);
30
+ $this->stream = new Stream($resource);
31
+ }
32
+
33
+ /**
34
+ * @param StreamInterface $stream
35
+ * @param $header
36
+ * @return int
37
+ */
38
+ private function getLengthOfPossibleFilenameHeader(StreamInterface $stream, $header)
39
+ {
40
+ $filename_header_length = 0;
41
+
42
+ if (substr(bin2hex($header), 6, 2) === '08') {
43
+ // we have a filename, read until nil
44
+ $filename_header_length = 1;
45
+ while ($stream->read(1) !== chr(0)) {
46
+ $filename_header_length++;
47
+ }
48
+ }
49
+
50
+ return $filename_header_length;
51
+ }
52
+ }
lib/Azure/GuzzleHttp/Psr7/LazyOpenStream.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Lazily reads or writes to a file that is opened only after an IO operation
8
+ * take place on the stream.
9
+ */
10
+ class LazyOpenStream implements StreamInterface
11
+ {
12
+ use StreamDecoratorTrait;
13
+
14
+ /** @var string File to open */
15
+ private $filename;
16
+
17
+ /** @var string $mode */
18
+ private $mode;
19
+
20
+ /**
21
+ * @param string $filename File to lazily open
22
+ * @param string $mode fopen mode to use when opening the stream
23
+ */
24
+ public function __construct($filename, $mode)
25
+ {
26
+ $this->filename = $filename;
27
+ $this->mode = $mode;
28
+ }
29
+
30
+ /**
31
+ * Creates the underlying stream lazily when required.
32
+ *
33
+ * @return StreamInterface
34
+ */
35
+ protected function createStream()
36
+ {
37
+ return stream_for(try_fopen($this->filename, $this->mode));
38
+ }
39
+ }
lib/Azure/GuzzleHttp/Psr7/LimitStream.php ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+
7
+ /**
8
+ * Decorator used to return only a subset of a stream
9
+ */
10
+ class LimitStream implements StreamInterface
11
+ {
12
+ use StreamDecoratorTrait;
13
+
14
+ /** @var int Offset to start reading from */
15
+ private $offset;
16
+
17
+ /** @var int Limit the number of bytes that can be read */
18
+ private $limit;
19
+
20
+ /**
21
+ * @param StreamInterface $stream Stream to wrap
22
+ * @param int $limit Total number of bytes to allow to be read
23
+ * from the stream. Pass -1 for no limit.
24
+ * @param int|null $offset Position to seek to before reading (only
25
+ * works on seekable streams).
26
+ */
27
+ public function __construct(
28
+ StreamInterface $stream,
29
+ $limit = -1,
30
+ $offset = 0
31
+ ) {
32
+ $this->stream = $stream;
33
+ $this->setLimit($limit);
34
+ $this->setOffset($offset);
35
+ }
36
+
37
+ public function eof()
38
+ {
39
+ // Always return true if the underlying stream is EOF
40
+ if ($this->stream->eof()) {
41
+ return true;
42
+ }
43
+
44
+ // No limit and the underlying stream is not at EOF
45
+ if ($this->limit == -1) {
46
+ return false;
47
+ }
48
+
49
+ return $this->stream->tell() >= $this->offset + $this->limit;
50
+ }
51
+
52
+ /**
53
+ * Returns the size of the limited subset of data
54
+ * {@inheritdoc}
55
+ */
56
+ public function getSize()
57
+ {
58
+ if (null === ($length = $this->stream->getSize())) {
59
+ return null;
60
+ } elseif ($this->limit == -1) {
61
+ return $length - $this->offset;
62
+ } else {
63
+ return min($this->limit, $length - $this->offset);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Allow for a bounded seek on the read limited stream
69
+ * {@inheritdoc}
70
+ */
71
+ public function seek($offset, $whence = SEEK_SET)
72
+ {
73
+ if ($whence !== SEEK_SET || $offset < 0) {
74
+ throw new \RuntimeException(sprintf(
75
+ 'Cannot seek to offset % with whence %s',
76
+ $offset,
77
+ $whence
78
+ ));
79
+ }
80
+
81
+ $offset += $this->offset;
82
+
83
+ if ($this->limit !== -1) {
84
+ if ($offset > $this->offset + $this->limit) {
85
+ $offset = $this->offset + $this->limit;
86
+ }
87
+ }
88
+
89
+ $this->stream->seek($offset);
90
+ }
91
+
92
+ /**
93
+ * Give a relative tell()
94
+ * {@inheritdoc}
95
+ */
96
+ public function tell()
97
+ {
98
+ return $this->stream->tell() - $this->offset;
99
+ }
100
+
101
+ /**
102
+ * Set the offset to start limiting from
103
+ *
104
+ * @param int $offset Offset to seek to and begin byte limiting from
105
+ *
106
+ * @throws \RuntimeException if the stream cannot be seeked.
107
+ */
108
+ public function setOffset($offset)
109
+ {
110
+ $current = $this->stream->tell();
111
+
112
+ if ($current !== $offset) {
113
+ // If the stream cannot seek to the offset position, then read to it
114
+ if ($this->stream->isSeekable()) {
115
+ $this->stream->seek($offset);
116
+ } elseif ($current > $offset) {
117
+ throw new \RuntimeException("Could not seek to stream offset $offset");
118
+ } else {
119
+ $this->stream->read($offset - $current);
120
+ }
121
+ }
122
+
123
+ $this->offset = $offset;
124
+ }
125
+
126
+ /**
127
+ * Set the limit of bytes that the decorator allows to be read from the
128
+ * stream.
129
+ *
130
+ * @param int $limit Number of bytes to allow to be read from the stream.
131
+ * Use -1 for no limit.
132
+ */
133
+ public function setLimit($limit)
134
+ {
135
+ $this->limit = $limit;
136
+ }
137
+
138
+ public function read($length)
139
+ {
140
+ if ($this->limit == -1) {
141
+ return $this->stream->read($length);
142
+ }
143
+
144
+ // Check if the current position is less than the total allowed
145
+ // bytes + original offset
146
+ $remaining = ($this->offset + $this->limit) - $this->stream->tell();
147
+ if ($remaining > 0) {
148
+ // Only return the amount of requested data, ensuring that the byte
149
+ // limit is not exceeded
150
+ return $this->stream->read(min($remaining, $length));
151
+ }
152
+
153
+ return '';
154
+ }
155
+ }
lib/Azure/GuzzleHttp/Psr7/MessageTrait.php ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Trait implementing functionality common to requests and responses.
8
+ */
9
+ trait MessageTrait
10
+ {
11
+ /** @var array Map of all registered headers, as original name => array of values */
12
+ private $headers = [];
13
+
14
+ /** @var array Map of lowercase header name => original name at registration */
15
+ private $headerNames = [];
16
+
17
+ /** @var string */
18
+ private $protocol = '1.1';
19
+
20
+ /** @var StreamInterface */
21
+ private $stream;
22
+
23
+ public function getProtocolVersion()
24
+ {
25
+ return $this->protocol;
26
+ }
27
+
28
+ public function withProtocolVersion($version)
29
+ {
30
+ if ($this->protocol === $version) {
31
+ return $this;
32
+ }
33
+
34
+ $new = clone $this;
35
+ $new->protocol = $version;
36
+ return $new;
37
+ }
38
+
39
+ public function getHeaders()
40
+ {
41
+ return $this->headers;
42
+ }
43
+
44
+ public function hasHeader($header)
45
+ {
46
+ return isset($this->headerNames[strtolower($header)]);
47
+ }
48
+
49
+ public function getHeader($header)
50
+ {
51
+ $header = strtolower($header);
52
+
53
+ if (!isset($this->headerNames[$header])) {
54
+ return [];
55
+ }
56
+
57
+ $header = $this->headerNames[$header];
58
+
59
+ return $this->headers[$header];
60
+ }
61
+
62
+ public function getHeaderLine($header)
63
+ {
64
+ return implode(', ', $this->getHeader($header));
65
+ }
66
+
67
+ public function withHeader($header, $value)
68
+ {
69
+ if (!is_array($value)) {
70
+ $value = [$value];
71
+ }
72
+
73
+ $value = $this->trimHeaderValues($value);
74
+ $normalized = strtolower($header);
75
+
76
+ $new = clone $this;
77
+ if (isset($new->headerNames[$normalized])) {
78
+ unset($new->headers[$new->headerNames[$normalized]]);
79
+ }
80
+ $new->headerNames[$normalized] = $header;
81
+ $new->headers[$header] = $value;
82
+
83
+ return $new;
84
+ }
85
+
86
+ public function withAddedHeader($header, $value)
87
+ {
88
+ if (!is_array($value)) {
89
+ $value = [$value];
90
+ }
91
+
92
+ $value = $this->trimHeaderValues($value);
93
+ $normalized = strtolower($header);
94
+
95
+ $new = clone $this;
96
+ if (isset($new->headerNames[$normalized])) {
97
+ $header = $this->headerNames[$normalized];
98
+ $new->headers[$header] = array_merge($this->headers[$header], $value);
99
+ } else {
100
+ $new->headerNames[$normalized] = $header;
101
+ $new->headers[$header] = $value;
102
+ }
103
+
104
+ return $new;
105
+ }
106
+
107
+ public function withoutHeader($header)
108
+ {
109
+ $normalized = strtolower($header);
110
+
111
+ if (!isset($this->headerNames[$normalized])) {
112
+ return $this;
113
+ }
114
+
115
+ $header = $this->headerNames[$normalized];
116
+
117
+ $new = clone $this;
118
+ unset($new->headers[$header], $new->headerNames[$normalized]);
119
+
120
+ return $new;
121
+ }
122
+
123
+ public function getBody()
124
+ {
125
+ if (!$this->stream) {
126
+ $this->stream = stream_for('');
127
+ }
128
+
129
+ return $this->stream;
130
+ }
131
+
132
+ public function withBody(StreamInterface $body)
133
+ {
134
+ if ($body === $this->stream) {
135
+ return $this;
136
+ }
137
+
138
+ $new = clone $this;
139
+ $new->stream = $body;
140
+ return $new;
141
+ }
142
+
143
+ private function setHeaders(array $headers)
144
+ {
145
+ $this->headerNames = $this->headers = [];
146
+ foreach ($headers as $header => $value) {
147
+ if (!is_array($value)) {
148
+ $value = [$value];
149
+ }
150
+
151
+ $value = $this->trimHeaderValues($value);
152
+ $normalized = strtolower($header);
153
+ if (isset($this->headerNames[$normalized])) {
154
+ $header = $this->headerNames[$normalized];
155
+ $this->headers[$header] = array_merge($this->headers[$header], $value);
156
+ } else {
157
+ $this->headerNames[$normalized] = $header;
158
+ $this->headers[$header] = $value;
159
+ }
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Trims whitespace from the header values.
165
+ *
166
+ * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field.
167
+ *
168
+ * header-field = field-name ":" OWS field-value OWS
169
+ * OWS = *( SP / HTAB )
170
+ *
171
+ * @param string[] $values Header values
172
+ *
173
+ * @return string[] Trimmed header values
174
+ *
175
+ * @see https://tools.ietf.org/html/rfc7230#section-3.2.4
176
+ */
177
+ private function trimHeaderValues(array $values)
178
+ {
179
+ return array_map(function ($value) {
180
+ return trim($value, " \t");
181
+ }, $values);
182
+ }
183
+ }
lib/Azure/GuzzleHttp/Psr7/MultipartStream.php ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Stream that when read returns bytes for a streaming multipart or
8
+ * multipart/form-data stream.
9
+ */
10
+ class MultipartStream implements StreamInterface
11
+ {
12
+ use StreamDecoratorTrait;
13
+
14
+ private $boundary;
15
+
16
+ /**
17
+ * @param array $elements Array of associative arrays, each containing a
18
+ * required "name" key mapping to the form field,
19
+ * name, a required "contents" key mapping to a
20
+ * StreamInterface/resource/string, an optional
21
+ * "headers" associative array of custom headers,
22
+ * and an optional "filename" key mapping to a
23
+ * string to send as the filename in the part.
24
+ * @param string $boundary You can optionally provide a specific boundary
25
+ *
26
+ * @throws \InvalidArgumentException
27
+ */
28
+ public function __construct(array $elements = [], $boundary = null)
29
+ {
30
+ $this->boundary = $boundary ?: uniqid();
31
+ $this->stream = $this->createStream($elements);
32
+ }
33
+
34
+ /**
35
+ * Get the boundary
36
+ *
37
+ * @return string
38
+ */
39
+ public function getBoundary()
40
+ {
41
+ return $this->boundary;
42
+ }
43
+
44
+ public function isWritable()
45
+ {
46
+ return false;
47
+ }
48
+
49
+ /**
50
+ * Get the headers needed before transferring the content of a POST file
51
+ */
52
+ private function getHeaders(array $headers)
53
+ {
54
+ $str = '';
55
+ foreach ($headers as $key => $value) {
56
+ $str .= "{$key}: {$value}\r\n";
57
+ }
58
+
59
+ return "--{$this->boundary}\r\n" . trim($str) . "\r\n\r\n";
60
+ }
61
+
62
+ /**
63
+ * Create the aggregate stream that will be used to upload the POST data
64
+ */
65
+ protected function createStream(array $elements)
66
+ {
67
+ $stream = new AppendStream();
68
+
69
+ foreach ($elements as $element) {
70
+ $this->addElement($stream, $element);
71
+ }
72
+
73
+ // Add the trailing boundary with CRLF
74
+ $stream->addStream(stream_for("--{$this->boundary}--\r\n"));
75
+
76
+ return $stream;
77
+ }
78
+
79
+ private function addElement(AppendStream $stream, array $element)
80
+ {
81
+ foreach (['contents', 'name'] as $key) {
82
+ if (!array_key_exists($key, $element)) {
83
+ throw new \InvalidArgumentException("A '{$key}' key is required");
84
+ }
85
+ }
86
+
87
+ $element['contents'] = stream_for($element['contents']);
88
+
89
+ if (empty($element['filename'])) {
90
+ $uri = $element['contents']->getMetadata('uri');
91
+ if (substr($uri, 0, 6) !== 'php://') {
92
+ $element['filename'] = $uri;
93
+ }
94
+ }
95
+
96
+ list($body, $headers) = $this->createElement(
97
+ $element['name'],
98
+ $element['contents'],
99
+ isset($element['filename']) ? $element['filename'] : null,
100
+ isset($element['headers']) ? $element['headers'] : []
101
+ );
102
+
103
+ $stream->addStream(stream_for($this->getHeaders($headers)));
104
+ $stream->addStream($body);
105
+ $stream->addStream(stream_for("\r\n"));
106
+ }
107
+
108
+ /**
109
+ * @return array
110
+ */
111
+ private function createElement($name, $stream, $filename, array $headers)
112
+ {
113
+ // Set a default content-disposition header if one was no provided
114
+ $disposition = $this->getHeader($headers, 'content-disposition');
115
+ if (!$disposition) {
116
+ $headers['Content-Disposition'] = ($filename === '0' || $filename)
117
+ ? sprintf('form-data; name="%s"; filename="%s"',
118
+ $name,
119
+ basename($filename))
120
+ : "form-data; name=\"{$name}\"";
121
+ }
122
+
123
+ // Set a default content-length header if one was no provided
124
+ $length = $this->getHeader($headers, 'content-length');
125
+ if (!$length) {
126
+ if ($length = $stream->getSize()) {
127
+ $headers['Content-Length'] = (string) $length;
128
+ }
129
+ }
130
+
131
+ // Set a default Content-Type if one was not supplied
132
+ $type = $this->getHeader($headers, 'content-type');
133
+ if (!$type && ($filename === '0' || $filename)) {
134
+ if ($type = mimetype_from_filename($filename)) {
135
+ $headers['Content-Type'] = $type;
136
+ }
137
+ }
138
+
139
+ return [$stream, $headers];
140
+ }
141
+
142
+ private function getHeader(array $headers, $key)
143
+ {
144
+ $lowercaseHeader = strtolower($key);
145
+ foreach ($headers as $k => $v) {
146
+ if (strtolower($k) === $lowercaseHeader) {
147
+ return $v;
148
+ }
149
+ }
150
+
151
+ return null;
152
+ }
153
+ }
lib/Azure/GuzzleHttp/Psr7/NoSeekStream.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Stream decorator that prevents a stream from being seeked
8
+ */
9
+ class NoSeekStream implements StreamInterface
10
+ {
11
+ use StreamDecoratorTrait;
12
+
13
+ public function seek($offset, $whence = SEEK_SET)
14
+ {
15
+ throw new \RuntimeException('Cannot seek a NoSeekStream');
16
+ }
17
+
18
+ public function isSeekable()
19
+ {
20
+ return false;
21
+ }
22
+ }
lib/Azure/GuzzleHttp/Psr7/PumpStream.php ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Provides a read only stream that pumps data from a PHP callable.
8
+ *
9
+ * When invoking the provided callable, the PumpStream will pass the amount of
10
+ * data requested to read to the callable. The callable can choose to ignore
11
+ * this value and return fewer or more bytes than requested. Any extra data
12
+ * returned by the provided callable is buffered internally until drained using
13
+ * the read() function of the PumpStream. The provided callable MUST return
14
+ * false when there is no more data to read.
15
+ */
16
+ class PumpStream implements StreamInterface
17
+ {
18
+ /** @var callable */
19
+ private $source;
20
+
21
+ /** @var int */
22
+ private $size;
23
+
24
+ /** @var int */
25
+ private $tellPos = 0;
26
+
27
+ /** @var array */
28
+ private $metadata;
29
+
30
+ /** @var BufferStream */
31
+ private $buffer;
32
+
33
+ /**
34
+ * @param callable $source Source of the stream data. The callable MAY
35
+ * accept an integer argument used to control the
36
+ * amount of data to return. The callable MUST
37
+ * return a string when called, or false on error
38
+ * or EOF.
39
+ * @param array $options Stream options:
40
+ * - metadata: Hash of metadata to use with stream.
41
+ * - size: Size of the stream, if known.
42
+ */
43
+ public function __construct(callable $source, array $options = [])
44
+ {
45
+ $this->source = $source;
46
+ $this->size = isset($options['size']) ? $options['size'] : null;
47
+ $this->metadata = isset($options['metadata']) ? $options['metadata'] : [];
48
+ $this->buffer = new BufferStream();
49
+ }
50
+
51
+ public function __toString()
52
+ {
53
+ try {
54
+ return copy_to_string($this);
55
+ } catch (\Exception $e) {
56
+ return '';
57
+ }
58
+ }
59
+
60
+ public function close()
61
+ {
62
+ $this->detach();
63
+ }
64
+
65
+ public function detach()
66
+ {
67
+ $this->tellPos = false;
68
+ $this->source = null;
69
+ }
70
+
71
+ public function getSize()
72
+ {
73
+ return $this->size;
74
+ }
75
+
76
+ public function tell()
77
+ {
78
+ return $this->tellPos;
79
+ }
80
+
81
+ public function eof()
82
+ {
83
+ return !$this->source;
84
+ }
85
+
86
+ public function isSeekable()
87
+ {
88
+ return false;
89
+ }
90
+
91
+ public function rewind()
92
+ {
93
+ $this->seek(0);
94
+ }
95
+
96
+ public function seek($offset, $whence = SEEK_SET)
97
+ {
98
+ throw new \RuntimeException('Cannot seek a PumpStream');
99
+ }
100
+
101
+ public function isWritable()
102
+ {
103
+ return false;
104
+ }
105
+
106
+ public function write($string)
107
+ {
108
+ throw new \RuntimeException('Cannot write to a PumpStream');
109
+ }
110
+
111
+ public function isReadable()
112
+ {
113
+ return true;
114
+ }
115
+
116
+ public function read($length)
117
+ {
118
+ $data = $this->buffer->read($length);
119
+ $readLen = strlen($data);
120
+ $this->tellPos += $readLen;
121
+ $remaining = $length - $readLen;
122
+
123
+ if ($remaining) {
124
+ $this->pump($remaining);
125
+ $data .= $this->buffer->read($remaining);
126
+ $this->tellPos += strlen($data) - $readLen;
127
+ }
128
+
129
+ return $data;
130
+ }
131
+
132
+ public function getContents()
133
+ {
134
+ $result = '';
135
+ while (!$this->eof()) {
136
+ $result .= $this->read(1000000);
137
+ }
138
+
139
+ return $result;
140
+ }
141
+
142
+ public function getMetadata($key = null)
143
+ {
144
+ if (!$key) {
145
+ return $this->metadata;
146
+ }
147
+
148
+ return isset($this->metadata[$key]) ? $this->metadata[$key] : null;
149
+ }
150
+
151
+ private function pump($length)
152
+ {
153
+ if ($this->source) {
154
+ do {
155
+ $data = call_user_func($this->source, $length);
156
+ if ($data === false || $data === null) {
157
+ $this->source = null;
158
+ return;
159
+ }
160
+ $this->buffer->write($data);
161
+ $length -= strlen($data);
162
+ } while ($length > 0);
163
+ }
164
+ }
165
+ }
lib/Azure/GuzzleHttp/Psr7/Request.php ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use InvalidArgumentException;
5
+ use Psr\Http\Message\RequestInterface;
6
+ use Psr\Http\Message\StreamInterface;
7
+ use Psr\Http\Message\UriInterface;
8
+
9
+ /**
10
+ * PSR-7 request implementation.
11
+ */
12
+ class Request implements RequestInterface
13
+ {
14
+ use MessageTrait;
15
+
16
+ /** @var string */
17
+ private $method;
18
+
19
+ /** @var null|string */
20
+ private $requestTarget;
21
+
22
+ /** @var null|UriInterface */
23
+ private $uri;
24
+
25
+ /**
26
+ * @param string $method HTTP method
27
+ * @param string|UriInterface $uri URI
28
+ * @param array $headers Request headers
29
+ * @param string|null|resource|StreamInterface $body Request body
30
+ * @param string $version Protocol version
31
+ */
32
+ public function __construct(
33
+ $method,
34
+ $uri,
35
+ array $headers = [],
36
+ $body = null,
37
+ $version = '1.1'
38
+ ) {
39
+ if (!($uri instanceof UriInterface)) {
40
+ $uri = new Uri($uri);
41
+ }
42
+
43
+ $this->method = strtoupper($method);
44
+ $this->uri = $uri;
45
+ $this->setHeaders($headers);
46
+ $this->protocol = $version;
47
+
48
+ if (!$this->hasHeader('Host')) {
49
+ $this->updateHostFromUri();
50
+ }
51
+
52
+ if ($body !== '' && $body !== null) {
53
+ $this->stream = stream_for($body);
54
+ }
55
+ }
56
+
57
+ public function getRequestTarget()
58
+ {
59
+ if ($this->requestTarget !== null) {
60
+ return $this->requestTarget;
61
+ }
62
+
63
+ $target = $this->uri->getPath();
64
+ if ($target == '') {
65
+ $target = '/';
66
+ }
67
+ if ($this->uri->getQuery() != '') {
68
+ $target .= '?' . $this->uri->getQuery();
69
+ }
70
+
71
+ return $target;
72
+ }
73
+
74
+ public function withRequestTarget($requestTarget)
75
+ {
76
+ if (preg_match('#\s#', $requestTarget)) {
77
+ throw new InvalidArgumentException(
78
+ 'Invalid request target provided; cannot contain whitespace'
79
+ );
80
+ }
81
+
82
+ $new = clone $this;
83
+ $new->requestTarget = $requestTarget;
84
+ return $new;
85
+ }
86
+
87
+ public function getMethod()
88
+ {
89
+ return $this->method;
90
+ }
91
+
92
+ public function withMethod($method)
93
+ {
94
+ $new = clone $this;
95
+ $new->method = strtoupper($method);
96
+ return $new;
97
+ }
98
+
99
+ public function getUri()
100
+ {
101
+ return $this->uri;
102
+ }
103
+
104
+ public function withUri(UriInterface $uri, $preserveHost = false)
105
+ {
106
+ if ($uri === $this->uri) {
107
+ return $this;
108
+ }
109
+
110
+ $new = clone $this;
111
+ $new->uri = $uri;
112
+
113
+ if (!$preserveHost) {
114
+ $new->updateHostFromUri();
115
+ }
116
+
117
+ return $new;
118
+ }
119
+
120
+ private function updateHostFromUri()
121
+ {
122
+ $host = $this->uri->getHost();
123
+
124
+ if ($host == '') {
125
+ return;
126
+ }
127
+
128
+ if (($port = $this->uri->getPort()) !== null) {
129
+ $host .= ':' . $port;
130
+ }
131
+
132
+ if (isset($this->headerNames['host'])) {
133
+ $header = $this->headerNames['host'];
134
+ } else {
135
+ $header = 'Host';
136
+ $this->headerNames['host'] = 'Host';
137
+ }
138
+ // Ensure Host is the first header.
139
+ // See: http://tools.ietf.org/html/rfc7230#section-5.4
140
+ $this->headers = [$header => [$host]] + $this->headers;
141
+ }
142
+ }
lib/Azure/GuzzleHttp/Psr7/Response.php ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\ResponseInterface;
5
+
6
+ /**
7
+ * PSR-7 response implementation.
8
+ */
9
+ class Response implements ResponseInterface
10
+ {
11
+ use MessageTrait;
12
+
13
+ /** @var array Map of standard HTTP status code/reason phrases */
14
+ private static $phrases = [
15
+ 100 => 'Continue',
16
+ 101 => 'Switching Protocols',
17
+ 102 => 'Processing',
18
+ 200 => 'OK',
19
+ 201 => 'Created',
20
+ 202 => 'Accepted',
21
+ 203 => 'Non-Authoritative Information',
22
+ 204 => 'No Content',
23
+ 205 => 'Reset Content',
24
+ 206 => 'Partial Content',
25
+ 207 => 'Multi-status',
26
+ 208 => 'Already Reported',
27
+ 300 => 'Multiple Choices',
28
+ 301 => 'Moved Permanently',
29
+ 302 => 'Found',
30
+ 303 => 'See Other',
31
+ 304 => 'Not Modified',
32
+ 305 => 'Use Proxy',
33
+ 306 => 'Switch Proxy',
34
+ 307 => 'Temporary Redirect',
35
+ 400 => 'Bad Request',
36
+ 401 => 'Unauthorized',
37
+ 402 => 'Payment Required',
38
+ 403 => 'Forbidden',
39
+ 404 => 'Not Found',
40
+ 405 => 'Method Not Allowed',
41
+ 406 => 'Not Acceptable',
42
+ 407 => 'Proxy Authentication Required',
43
+ 408 => 'Request Time-out',
44
+ 409 => 'Conflict',
45
+ 410 => 'Gone',
46
+ 411 => 'Length Required',
47
+ 412 => 'Precondition Failed',
48
+ 413 => 'Request Entity Too Large',
49
+ 414 => 'Request-URI Too Large',
50
+ 415 => 'Unsupported Media Type',
51
+ 416 => 'Requested range not satisfiable',
52
+ 417 => 'Expectation Failed',
53
+ 418 => 'I\'m a teapot',
54
+ 422 => 'Unprocessable Entity',
55
+ 423 => 'Locked',
56
+ 424 => 'Failed Dependency',
57
+ 425 => 'Unordered Collection',
58
+ 426 => 'Upgrade Required',
59
+ 428 => 'Precondition Required',
60
+ 429 => 'Too Many Requests',
61
+ 431 => 'Request Header Fields Too Large',
62
+ 451 => 'Unavailable For Legal Reasons',
63
+ 500 => 'Internal Server Error',
64
+ 501 => 'Not Implemented',
65
+ 502 => 'Bad Gateway',
66
+ 503 => 'Service Unavailable',
67
+ 504 => 'Gateway Time-out',
68
+ 505 => 'HTTP Version not supported',
69
+ 506 => 'Variant Also Negotiates',
70
+ 507 => 'Insufficient Storage',
71
+ 508 => 'Loop Detected',
72
+ 511 => 'Network Authentication Required',
73
+ ];
74
+
75
+ /** @var string */
76
+ private $reasonPhrase = '';
77
+
78
+ /** @var int */
79
+ private $statusCode = 200;
80
+
81
+ /**
82
+ * @param int $status Status code
83
+ * @param array $headers Response headers
84
+ * @param string|null|resource|StreamInterface $body Response body
85
+ * @param string $version Protocol version
86
+ * @param string|null $reason Reason phrase (when empty a default will be used based on the status code)
87
+ */
88
+ public function __construct(
89
+ $status = 200,
90
+ array $headers = [],
91
+ $body = null,
92
+ $version = '1.1',
93
+ $reason = null
94
+ ) {
95
+ $this->statusCode = (int) $status;
96
+
97
+ if ($body !== '' && $body !== null) {
98
+ $this->stream = stream_for($body);
99
+ }
100
+
101
+ $this->setHeaders($headers);
102
+ if ($reason == '' && isset(self::$phrases[$this->statusCode])) {
103
+ $this->reasonPhrase = self::$phrases[$status];
104
+ } else {
105
+ $this->reasonPhrase = (string) $reason;
106
+ }
107
+
108
+ $this->protocol = $version;
109
+ }
110
+
111
+ public function getStatusCode()
112
+ {
113
+ return $this->statusCode;
114
+ }
115
+
116
+ public function getReasonPhrase()
117
+ {
118
+ return $this->reasonPhrase;
119
+ }
120
+
121
+ public function withStatus($code, $reasonPhrase = '')
122
+ {
123
+ $new = clone $this;
124
+ $new->statusCode = (int) $code;
125
+ if ($reasonPhrase == '' && isset(self::$phrases[$new->statusCode])) {
126
+ $reasonPhrase = self::$phrases[$new->statusCode];
127
+ }
128
+ $new->reasonPhrase = $reasonPhrase;
129
+ return $new;
130
+ }
131
+ }
lib/Azure/GuzzleHttp/Psr7/ServerRequest.php ADDED
@@ -0,0 +1,346 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace GuzzleHttp\Psr7;
4
+
5
+ use InvalidArgumentException;
6
+ use Psr\Http\Message\ServerRequestInterface;
7
+ use Psr\Http\Message\UriInterface;
8
+ use Psr\Http\Message\StreamInterface;
9
+ use Psr\Http\Message\UploadedFileInterface;
10
+
11
+ /**
12
+ * Server-side HTTP request
13
+ *
14
+ * Extends the Request definition to add methods for accessing incoming data,
15
+ * specifically server parameters, cookies, matched path parameters, query
16
+ * string arguments, body parameters, and upload file information.
17
+ *
18
+ * "Attributes" are discovered via decomposing the request (and usually
19
+ * specifically the URI path), and typically will be injected by the application.
20
+ *
21
+ * Requests are considered immutable; all methods that might change state are
22
+ * implemented such that they retain the internal state of the current
23
+ * message and return a new instance that contains the changed state.
24
+ */
25
+ class ServerRequest extends Request implements ServerRequestInterface
26
+ {
27
+ /**
28
+ * @var array
29
+ */
30
+ private $attributes = [];
31
+
32
+ /**
33
+ * @var array
34
+ */
35
+ private $cookieParams = [];
36
+
37
+ /**
38
+ * @var null|array|object
39
+ */
40
+ private $parsedBody;
41
+
42
+ /**
43
+ * @var array
44
+ */
45
+ private $queryParams = [];
46
+
47
+ /**
48
+ * @var array
49
+ */
50
+ private $serverParams;
51
+
52
+ /**
53
+ * @var array
54
+ */
55
+ private $uploadedFiles = [];
56
+
57
+ /**
58
+ * @param string $method HTTP method
59
+ * @param string|UriInterface $uri URI
60
+ * @param array $headers Request headers
61
+ * @param string|null|resource|StreamInterface $body Request body
62
+ * @param string $version Protocol version
63
+ * @param array $serverParams Typically the $_SERVER superglobal
64
+ */
65
+ public function __construct(
66
+ $method,
67
+ $uri,
68
+ array $headers = [],
69
+ $body = null,
70
+ $version = '1.1',
71
+ array $serverParams = []
72
+ ) {
73
+ $this->serverParams = $serverParams;
74
+
75
+ parent::__construct($method, $uri, $headers, $body, $version);
76
+ }
77
+
78
+ /**
79
+ * Return an UploadedFile instance array.
80
+ *
81
+ * @param array $files A array which respect $_FILES structure
82
+ * @throws InvalidArgumentException for unrecognized values
83
+ * @return array
84
+ */
85
+ public static function normalizeFiles(array $files)
86
+ {
87
+ $normalized = [];
88
+
89
+ foreach ($files as $key => $value) {
90
+ if ($value instanceof UploadedFileInterface) {
91
+ $normalized[$key] = $value;
92
+ } elseif (is_array($value) && isset($value['tmp_name'])) {
93
+ $normalized[$key] = self::createUploadedFileFromSpec($value);
94
+ } elseif (is_array($value)) {
95
+ $normalized[$key] = self::normalizeFiles($value);
96
+ continue;
97
+ } else {
98
+ throw new InvalidArgumentException('Invalid value in files specification');
99
+ }
100
+ }
101
+
102
+ return $normalized;
103
+ }
104
+
105
+ /**
106
+ * Create and return an UploadedFile instance from a $_FILES specification.
107
+ *
108
+ * If the specification represents an array of values, this method will
109
+ * delegate to normalizeNestedFileSpec() and return that return value.
110
+ *
111
+ * @param array $value $_FILES struct
112
+ * @return array|UploadedFileInterface
113
+ */
114
+ private static function createUploadedFileFromSpec(array $value)
115
+ {
116
+ if (is_array($value['tmp_name'])) {
117
+ return self::normalizeNestedFileSpec($value);
118
+ }
119
+
120
+ return new UploadedFile(
121
+ $value['tmp_name'],
122
+ (int) $value['size'],
123
+ (int) $value['error'],
124
+ $value['name'],
125
+ $value['type']
126
+ );
127
+ }
128
+
129
+ /**
130
+ * Normalize an array of file specifications.
131
+ *
132
+ * Loops through all nested files and returns a normalized array of
133
+ * UploadedFileInterface instances.
134
+ *
135
+ * @param array $files
136
+ * @return UploadedFileInterface[]
137
+ */
138
+ private static function normalizeNestedFileSpec(array $files = [])
139
+ {
140
+ $normalizedFiles = [];
141
+
142
+ foreach (array_keys($files['tmp_name']) as $key) {
143
+ $spec = [
144
+ 'tmp_name' => $files['tmp_name'][$key],
145
+ 'size' => $files['size'][$key],
146
+ 'error' => $files['error'][$key],
147
+ 'name' => $files['name'][$key],
148
+ 'type' => $files['type'][$key],
149
+ ];
150
+ $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
151
+ }
152
+
153
+ return $normalizedFiles;
154
+ }
155
+
156
+ /**
157
+ * Return a ServerRequest populated with superglobals:
158
+ * $_GET
159
+ * $_POST
160
+ * $_COOKIE
161
+ * $_FILES
162
+ * $_SERVER
163
+ *
164
+ * @return ServerRequestInterface
165
+ */
166
+ public static function fromGlobals()
167
+ {
168
+ $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
169
+ $headers = function_exists('getallheaders') ? getallheaders() : [];
170
+ $uri = self::getUriFromGlobals();
171
+ $body = new LazyOpenStream('php://input', 'r+');
172
+ $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';
173
+
174
+ $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER);
175
+
176
+ return $serverRequest
177
+ ->withCookieParams($_COOKIE)
178
+ ->withQueryParams($_GET)
179
+ ->withParsedBody($_POST)
180
+ ->withUploadedFiles(self::normalizeFiles($_FILES));
181
+ }
182
+
183
+ /**
184
+ * Get a Uri populated with values from $_SERVER.
185
+ *
186
+ * @return UriInterface
187
+ */
188
+ public static function getUriFromGlobals() {
189
+ $uri = new Uri('');
190
+
191
+ if (isset($_SERVER['HTTPS'])) {
192
+ $uri = $uri->withScheme($_SERVER['HTTPS'] == 'on' ? 'https' : 'http');
193
+ }
194
+
195
+ if (isset($_SERVER['HTTP_HOST'])) {
196
+ $uri = $uri->withHost($_SERVER['HTTP_HOST']);
197
+ } elseif (isset($_SERVER['SERVER_NAME'])) {
198
+ $uri = $uri->withHost($_SERVER['SERVER_NAME']);
199
+ }
200
+
201
+ if (isset($_SERVER['SERVER_PORT'])) {
202
+ $uri = $uri->withPort($_SERVER['SERVER_PORT']);
203
+ }
204
+
205
+ if (isset($_SERVER['REQUEST_URI'])) {
206
+ $uri = $uri->withPath(current(explode('?', $_SERVER['REQUEST_URI'])));
207
+ }
208
+
209
+ if (isset($_SERVER['QUERY_STRING'])) {
210
+ $uri = $uri->withQuery($_SERVER['QUERY_STRING']);
211
+ }
212
+
213
+ return $uri;
214
+ }
215
+
216
+
217
+ /**
218
+ * {@inheritdoc}
219
+ */
220
+ public function getServerParams()
221
+ {
222
+ return $this->serverParams;
223
+ }
224
+
225
+ /**
226
+ * {@inheritdoc}
227
+ */
228
+ public function getUploadedFiles()
229
+ {
230
+ return $this->uploadedFiles;
231
+ }
232
+
233
+ /**
234
+ * {@inheritdoc}
235
+ */
236
+ public function withUploadedFiles(array $uploadedFiles)
237
+ {
238
+ $new = clone $this;
239
+ $new->uploadedFiles = $uploadedFiles;
240
+
241
+ return $new;
242
+ }
243
+
244
+ /**
245
+ * {@inheritdoc}
246
+ */
247
+ public function getCookieParams()
248
+ {
249
+ return $this->cookieParams;
250
+ }
251
+
252
+ /**
253
+ * {@inheritdoc}
254
+ */
255
+ public function withCookieParams(array $cookies)
256
+ {
257
+ $new = clone $this;
258
+ $new->cookieParams = $cookies;
259
+
260
+ return $new;
261
+ }
262
+
263
+ /**
264
+ * {@inheritdoc}
265
+ */
266
+ public function getQueryParams()
267
+ {
268
+ return $this->queryParams;
269
+ }
270
+
271
+ /**
272
+ * {@inheritdoc}
273
+ */
274
+ public function withQueryParams(array $query)
275
+ {
276
+ $new = clone $this;
277
+ $new->queryParams = $query;
278
+
279
+ return $new;
280
+ }
281
+
282
+ /**
283
+ * {@inheritdoc}
284
+ */
285
+ public function getParsedBody()
286
+ {
287
+ return $this->parsedBody;
288
+ }
289
+
290
+ /**
291
+ * {@inheritdoc}
292
+ */
293
+ public function withParsedBody($data)
294
+ {
295
+ $new = clone $this;
296
+ $new->parsedBody = $data;
297
+
298
+ return $new;
299
+ }
300
+
301
+ /**
302
+ * {@inheritdoc}
303
+ */
304
+ public function getAttributes()
305
+ {
306
+ return $this->attributes;
307
+ }
308
+
309
+ /**
310
+ * {@inheritdoc}
311
+ */
312
+ public function getAttribute($attribute, $default = null)
313
+ {
314
+ if (false === array_key_exists($attribute, $this->attributes)) {
315
+ return $default;
316
+ }
317
+
318
+ return $this->attributes[$attribute];
319
+ }
320
+
321
+ /**
322
+ * {@inheritdoc}
323
+ */
324
+ public function withAttribute($attribute, $value)
325
+ {
326
+ $new = clone $this;
327
+ $new->attributes[$attribute] = $value;
328
+
329
+ return $new;
330
+ }
331
+
332
+ /**
333
+ * {@inheritdoc}
334
+ */
335
+ public function withoutAttribute($attribute)
336
+ {
337
+ if (false === array_key_exists($attribute, $this->attributes)) {
338
+ return $this;
339
+ }
340
+
341
+ $new = clone $this;
342
+ unset($new->attributes[$attribute]);
343
+
344
+ return $new;
345
+ }
346
+ }
lib/Azure/GuzzleHttp/Psr7/Stream.php ADDED
@@ -0,0 +1,245 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * PHP stream implementation.
8
+ *
9
+ * @var $stream
10
+ */
11
+ class Stream implements StreamInterface
12
+ {
13
+ private $stream;
14
+ private $size;
15
+ private $seekable;
16
+ private $readable;
17
+ private $writable;
18
+ private $uri;
19
+ private $customMetadata;
20
+
21
+ /** @var array Hash of readable and writable stream types */
22
+ private static $readWriteHash = [
23
+ 'read' => [
24
+ 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
25
+ 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true,
26
+ 'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true,
27
+ 'x+t' => true, 'c+t' => true, 'a+' => true
28
+ ],
29
+ 'write' => [
30
+ 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true,
31
+ 'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true,
32
+ 'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true,
33
+ 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true
34
+ ]
35
+ ];
36
+
37
+ /**
38
+ * This constructor accepts an associative array of options.
39
+ *
40
+ * - size: (int) If a read stream would otherwise have an indeterminate
41
+ * size, but the size is known due to foreknowledge, then you can
42
+ * provide that size, in bytes.
43
+ * - metadata: (array) Any additional metadata to return when the metadata
44
+ * of the stream is accessed.
45
+ *
46
+ * @param resource $stream Stream resource to wrap.
47
+ * @param array $options Associative array of options.
48
+ *
49
+ * @throws \InvalidArgumentException if the stream is not a stream resource
50
+ */
51
+ public function __construct($stream, $options = [])
52
+ {
53
+ if (!is_resource($stream)) {
54
+ throw new \InvalidArgumentException('Stream must be a resource');
55
+ }
56
+
57
+ if (isset($options['size'])) {
58
+ $this->size = $options['size'];
59
+ }
60
+
61
+ $this->customMetadata = isset($options['metadata'])
62
+ ? $options['metadata']
63
+ : [];
64
+
65
+ $this->stream = $stream;
66
+ $meta = stream_get_meta_data($this->stream);
67
+ $this->seekable = $meta['seekable'];
68
+ $this->readable = isset(self::$readWriteHash['read'][$meta['mode']]);
69
+ $this->writable = isset(self::$readWriteHash['write'][$meta['mode']]);
70
+ $this->uri = $this->getMetadata('uri');
71
+ }
72
+
73
+ public function __get($name)
74
+ {
75
+ if ($name == 'stream') {
76
+ throw new \RuntimeException('The stream is detached');
77
+ }
78
+
79
+ throw new \BadMethodCallException('No value for ' . $name);
80
+ }
81
+
82
+ /**
83
+ * Closes the stream when the destructed
84
+ */
85
+ public function __destruct()
86
+ {
87
+ $this->close();
88
+ }
89
+
90
+ public function __toString()
91
+ {
92
+ try {
93
+ $this->seek(0);
94
+ return (string) stream_get_contents($this->stream);
95
+ } catch (\Exception $e) {
96
+ return '';
97
+ }
98
+ }
99
+
100
+ public function getContents()
101
+ {
102
+ $contents = stream_get_contents($this->stream);
103
+
104
+ if ($contents === false) {
105
+ throw new \RuntimeException('Unable to read stream contents');
106
+ }
107
+
108
+ return $contents;
109
+ }
110
+
111
+ public function close()
112
+ {
113
+ if (isset($this->stream)) {
114
+ if (is_resource($this->stream)) {
115
+ fclose($this->stream);
116
+ }
117
+ $this->detach();
118
+ }
119
+ }
120
+
121
+ public function detach()
122
+ {
123
+ if (!isset($this->stream)) {
124
+ return null;
125
+ }
126
+
127
+ $result = $this->stream;
128
+ unset($this->stream);
129
+ $this->size = $this->uri = null;
130
+ $this->readable = $this->writable = $this->seekable = false;
131
+
132
+ return $result;
133
+ }
134
+
135
+ public function getSize()
136
+ {
137
+ if ($this->size !== null) {
138
+ return $this->size;
139
+ }
140
+
141
+ if (!isset($this->stream)) {
142
+ return null;
143
+ }
144
+
145
+ // Clear the stat cache if the stream has a URI
146
+ if ($this->uri) {
147
+ clearstatcache(true, $this->uri);
148
+ }
149
+
150
+ $stats = fstat($this->stream);
151
+ if (isset($stats['size'])) {
152
+ $this->size = $stats['size'];
153
+ return $this->size;
154
+ }
155
+
156
+ return null;
157
+ }
158
+
159
+ public function isReadable()
160
+ {
161
+ return $this->readable;
162
+ }
163
+
164
+ public function isWritable()
165
+ {
166
+ return $this->writable;
167
+ }
168
+
169
+ public function isSeekable()
170
+ {
171
+ return $this->seekable;
172
+ }
173
+
174
+ public function eof()
175
+ {
176
+ return !$this->stream || feof($this->stream);
177
+ }
178
+
179
+ public function tell()
180
+ {
181
+ $result = ftell($this->stream);
182
+
183
+ if ($result === false) {
184
+ throw new \RuntimeException('Unable to determine stream position');
185
+ }
186
+
187
+ return $result;
188
+ }
189
+
190
+ public function rewind()
191
+ {
192
+ $this->seek(0);
193
+ }
194
+
195
+ public function seek($offset, $whence = SEEK_SET)
196
+ {
197
+ if (!$this->seekable) {
198
+ throw new \RuntimeException('Stream is not seekable');
199
+ } elseif (fseek($this->stream, $offset, $whence) === -1) {
200
+ throw new \RuntimeException('Unable to seek to stream position '
201
+ . $offset . ' with whence ' . var_export($whence, true));
202
+ }
203
+ }
204
+
205
+ public function read($length)
206
+ {
207
+ if (!$this->readable) {
208
+ throw new \RuntimeException('Cannot read from non-readable stream');
209
+ }
210
+
211
+ return fread($this->stream, $length);
212
+ }
213
+
214
+ public function write($string)
215
+ {
216
+ if (!$this->writable) {
217
+ throw new \RuntimeException('Cannot write to a non-writable stream');
218
+ }
219
+
220
+ // We can't know the size after writing anything
221
+ $this->size = null;
222
+ $result = fwrite($this->stream, $string);
223
+
224
+ if ($result === false) {
225
+ throw new \RuntimeException('Unable to write to stream');
226
+ }
227
+
228
+ return $result;
229
+ }
230
+
231
+ public function getMetadata($key = null)
232
+ {
233
+ if (!isset($this->stream)) {
234
+ return $key ? null : [];
235
+ } elseif (!$key) {
236
+ return $this->customMetadata + stream_get_meta_data($this->stream);
237
+ } elseif (isset($this->customMetadata[$key])) {
238
+ return $this->customMetadata[$key];
239
+ }
240
+
241
+ $meta = stream_get_meta_data($this->stream);
242
+
243
+ return isset($meta[$key]) ? $meta[$key] : null;
244
+ }
245
+ }
lib/Azure/GuzzleHttp/Psr7/StreamDecoratorTrait.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Stream decorator trait
8
+ * @property StreamInterface stream
9
+ */
10
+ trait StreamDecoratorTrait
11
+ {
12
+ /**
13
+ * @param StreamInterface $stream Stream to decorate
14
+ */
15
+ public function __construct(StreamInterface $stream)
16
+ {
17
+ $this->stream = $stream;
18
+ }
19
+
20
+ /**
21
+ * Magic method used to create a new stream if streams are not added in
22
+ * the constructor of a decorator (e.g., LazyOpenStream).
23
+ *
24
+ * @param string $name Name of the property (allows "stream" only).
25
+ *
26
+ * @return StreamInterface
27
+ */
28
+ public function __get($name)
29
+ {
30
+ if ($name == 'stream') {
31
+ $this->stream = $this->createStream();
32
+ return $this->stream;
33
+ }
34
+
35
+ throw new \UnexpectedValueException("$name not found on class");
36
+ }
37
+
38
+ public function __toString()
39
+ {
40
+ try {
41
+ if ($this->isSeekable()) {
42
+ $this->seek(0);
43
+ }
44
+ return $this->getContents();
45
+ } catch (\Exception $e) {
46
+ // Really, PHP? https://bugs.php.net/bug.php?id=53648
47
+ trigger_error('StreamDecorator::__toString exception: '
48
+ . (string) $e, E_USER_ERROR);
49
+ return '';
50
+ }
51
+ }
52
+
53
+ public function getContents()
54
+ {
55
+ return copy_to_string($this);
56
+ }
57
+
58
+ /**
59
+ * Allow decorators to implement custom methods
60
+ *
61
+ * @param string $method Missing method name
62
+ * @param array $args Method arguments
63
+ *
64
+ * @return mixed
65
+ */
66
+ public function __call($method, array $args)
67
+ {
68
+ $result = call_user_func_array([$this->stream, $method], $args);
69
+
70
+ // Always return the wrapped object if the result is a return $this
71
+ return $result === $this->stream ? $this : $result;
72
+ }
73
+
74
+ public function close()
75
+ {
76
+ $this->stream->close();
77
+ }
78
+
79
+ public function getMetadata($key = null)
80
+ {
81
+ return $this->stream->getMetadata($key);
82
+ }
83
+
84
+ public function detach()
85
+ {
86
+ return $this->stream->detach();
87
+ }
88
+
89
+ public function getSize()
90
+ {
91
+ return $this->stream->getSize();
92
+ }
93
+
94
+ public function eof()
95
+ {
96
+ return $this->stream->eof();
97
+ }
98
+
99
+ public function tell()
100
+ {
101
+ return $this->stream->tell();
102
+ }
103
+
104
+ public function isReadable()
105
+ {
106
+ return $this->stream->isReadable();
107
+ }
108
+
109
+ public function isWritable()
110
+ {
111
+ return $this->stream->isWritable();
112
+ }
113
+
114
+ public function isSeekable()
115
+ {
116
+ return $this->stream->isSeekable();
117
+ }
118
+
119
+ public function rewind()
120
+ {
121
+ $this->seek(0);
122
+ }
123
+
124
+ public function seek($offset, $whence = SEEK_SET)
125
+ {
126
+ $this->stream->seek($offset, $whence);
127
+ }
128
+
129
+ public function read($length)
130
+ {
131
+ return $this->stream->read($length);
132
+ }
133
+
134
+ public function write($string)
135
+ {
136
+ return $this->stream->write($string);
137
+ }
138
+
139
+ /**
140
+ * Implement in subclasses to dynamically create streams when requested.
141
+ *
142
+ * @return StreamInterface
143
+ * @throws \BadMethodCallException
144
+ */
145
+ protected function createStream()
146
+ {
147
+ throw new \BadMethodCallException('Not implemented');
148
+ }
149
+ }
lib/Azure/GuzzleHttp/Psr7/StreamWrapper.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\StreamInterface;
5
+
6
+ /**
7
+ * Converts Guzzle streams into PHP stream resources.
8
+ */
9
+ class StreamWrapper
10
+ {
11
+ /** @var resource */
12
+ public $context;
13
+
14
+ /** @var StreamInterface */
15
+ private $stream;
16
+
17
+ /** @var string r, r+, or w */
18
+ private $mode;
19
+
20
+ /**
21
+ * Returns a resource representing the stream.
22
+ *
23
+ * @param StreamInterface $stream The stream to get a resource for
24
+ *
25
+ * @return resource
26
+ * @throws \InvalidArgumentException if stream is not readable or writable
27
+ */
28
+ public static function getResource(StreamInterface $stream)
29
+ {
30
+ self::register();
31
+
32
+ if ($stream->isReadable()) {
33
+ $mode = $stream->isWritable() ? 'r+' : 'r';
34
+ } elseif ($stream->isWritable()) {
35
+ $mode = 'w';
36
+ } else {
37
+ throw new \InvalidArgumentException('The stream must be readable, '
38
+ . 'writable, or both.');
39
+ }
40
+
41
+ return fopen('guzzle://stream', $mode, null, stream_context_create([
42
+ 'guzzle' => ['stream' => $stream]
43
+ ]));
44
+ }
45
+
46
+ /**
47
+ * Registers the stream wrapper if needed
48
+ */
49
+ public static function register()
50
+ {
51
+ if (!in_array('guzzle', stream_get_wrappers())) {
52
+ stream_wrapper_register('guzzle', __CLASS__);
53
+ }
54
+ }
55
+
56
+ public function stream_open($path, $mode, $options, &$opened_path)
57
+ {
58
+ $options = stream_context_get_options($this->context);
59
+
60
+ if (!isset($options['guzzle']['stream'])) {
61
+ return false;
62
+ }
63
+
64
+ $this->mode = $mode;
65
+ $this->stream = $options['guzzle']['stream'];
66
+
67
+ return true;
68
+ }
69
+
70
+ public function stream_read($count)
71
+ {
72
+ return $this->stream->read($count);
73
+ }
74
+
75
+ public function stream_write($data)
76
+ {
77
+ return (int) $this->stream->write($data);
78
+ }
79
+
80
+ public function stream_tell()
81
+ {
82
+ return $this->stream->tell();
83
+ }
84
+
85
+ public function stream_eof()
86
+ {
87
+ return $this->stream->eof();
88
+ }
89
+
90
+ public function stream_seek($offset, $whence)
91
+ {
92
+ $this->stream->seek($offset, $whence);
93
+
94
+ return true;
95
+ }
96
+
97
+ public function stream_stat()
98
+ {
99
+ static $modeMap = [
100
+ 'r' => 33060,
101
+ 'r+' => 33206,
102
+ 'w' => 33188
103
+ ];
104
+
105
+ return [
106
+ 'dev' => 0,
107
+ 'ino' => 0,
108
+ 'mode' => $modeMap[$this->mode],
109
+ 'nlink' => 0,
110
+ 'uid' => 0,
111
+ 'gid' => 0,
112
+ 'rdev' => 0,
113
+ 'size' => $this->stream->getSize() ?: 0,
114
+ 'atime' => 0,
115
+ 'mtime' => 0,
116
+ 'ctime' => 0,
117
+ 'blksize' => 0,
118
+ 'blocks' => 0
119
+ ];
120
+ }
121
+ }
lib/Azure/GuzzleHttp/Psr7/UploadedFile.php ADDED
@@ -0,0 +1,316 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use InvalidArgumentException;
5
+ use Psr\Http\Message\StreamInterface;
6
+ use Psr\Http\Message\UploadedFileInterface;
7
+ use RuntimeException;
8
+
9
+ class UploadedFile implements UploadedFileInterface
10
+ {
11
+ /**
12
+ * @var int[]
13
+ */
14
+ private static $errors = [
15
+ UPLOAD_ERR_OK,
16
+ UPLOAD_ERR_INI_SIZE,
17
+ UPLOAD_ERR_FORM_SIZE,
18
+ UPLOAD_ERR_PARTIAL,
19
+ UPLOAD_ERR_NO_FILE,
20
+ UPLOAD_ERR_NO_TMP_DIR,
21
+ UPLOAD_ERR_CANT_WRITE,
22
+ UPLOAD_ERR_EXTENSION,
23
+ ];
24
+
25
+ /**
26
+ * @var string
27
+ */
28
+ private $clientFilename;
29
+
30
+ /**
31
+ * @var string
32
+ */
33
+ private $clientMediaType;
34
+
35
+ /**
36
+ * @var int
37
+ */
38
+ private $error;
39
+
40
+ /**
41
+ * @var null|string
42
+ */
43
+ private $file;
44
+
45
+ /**
46
+ * @var bool
47
+ */
48
+ private $moved = false;
49
+
50
+ /**
51
+ * @var int
52
+ */
53
+ private $size;
54
+
55
+ /**
56
+ * @var StreamInterface|null
57
+ */
58
+ private $stream;
59
+
60
+ /**
61
+ * @param StreamInterface|string|resource $streamOrFile
62
+ * @param int $size
63
+ * @param int $errorStatus
64
+ * @param string|null $clientFilename
65
+ * @param string|null $clientMediaType
66
+ */
67
+ public function __construct(
68
+ $streamOrFile,
69
+ $size,
70
+ $errorStatus,
71
+ $clientFilename = null,
72
+ $clientMediaType = null
73
+ ) {
74
+ $this->setError($errorStatus);
75
+ $this->setSize($size);
76
+ $this->setClientFilename($clientFilename);
77
+ $this->setClientMediaType($clientMediaType);
78
+
79
+ if ($this->isOk()) {
80
+ $this->setStreamOrFile($streamOrFile);
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Depending on the value set file or stream variable
86
+ *
87
+ * @param mixed $streamOrFile
88
+ * @throws InvalidArgumentException
89
+ */
90
+ private function setStreamOrFile($streamOrFile)
91
+ {
92
+ if (is_string($streamOrFile)) {
93
+ $this->file = $streamOrFile;
94
+ } elseif (is_resource($streamOrFile)) {
95
+ $this->stream = new Stream($streamOrFile);
96
+ } elseif ($streamOrFile instanceof StreamInterface) {
97
+ $this->stream = $streamOrFile;
98
+ } else {
99
+ throw new InvalidArgumentException(
100
+ 'Invalid stream or file provided for UploadedFile'
101
+ );
102
+ }
103
+ }
104
+
105
+ /**
106
+ * @param int $error
107
+ * @throws InvalidArgumentException
108
+ */
109
+ private function setError($error)
110
+ {
111
+ if (false === is_int($error)) {
112
+ throw new InvalidArgumentException(
113
+ 'Upload file error status must be an integer'
114
+ );
115
+ }
116
+
117
+ if (false === in_array($error, UploadedFile::$errors)) {
118
+ throw new InvalidArgumentException(
119
+ 'Invalid error status for UploadedFile'
120
+ );
121
+ }
122
+
123
+ $this->error = $error;
124
+ }
125
+
126
+ /**
127
+ * @param int $size
128
+ * @throws InvalidArgumentException
129
+ */
130
+ private function setSize($size)
131
+ {
132
+ if (false === is_int($size)) {
133
+ throw new InvalidArgumentException(
134
+ 'Upload file size must be an integer'
135
+ );
136
+ }
137
+
138
+ $this->size = $size;
139
+ }
140
+
141
+ /**
142
+ * @param mixed $param
143
+ * @return boolean
144
+ */
145
+ private function isStringOrNull($param)
146
+ {
147
+ return in_array(gettype($param), ['string', 'NULL']);
148
+ }
149
+
150
+ /**
151
+ * @param mixed $param
152
+ * @return boolean
153
+ */
154
+ private function isStringNotEmpty($param)
155
+ {
156
+ return is_string($param) && false === empty($param);
157
+ }
158
+
159
+ /**
160
+ * @param string|null $clientFilename
161
+ * @throws InvalidArgumentException
162
+ */
163
+ private function setClientFilename($clientFilename)
164
+ {
165
+ if (false === $this->isStringOrNull($clientFilename)) {
166
+ throw new InvalidArgumentException(
167
+ 'Upload file client filename must be a string or null'
168
+ );
169
+ }
170
+
171
+ $this->clientFilename = $clientFilename;
172
+ }
173
+
174
+ /**
175
+ * @param string|null $clientMediaType
176
+ * @throws InvalidArgumentException
177
+ */
178
+ private function setClientMediaType($clientMediaType)
179
+ {
180
+ if (false === $this->isStringOrNull($clientMediaType)) {
181
+ throw new InvalidArgumentException(
182
+ 'Upload file client media type must be a string or null'
183
+ );
184
+ }
185
+
186
+ $this->clientMediaType = $clientMediaType;
187
+ }
188
+
189
+ /**
190
+ * Return true if there is no upload error
191
+ *
192
+ * @return boolean
193
+ */
194
+ private function isOk()
195
+ {
196
+ return $this->error === UPLOAD_ERR_OK;
197
+ }
198
+
199
+ /**
200
+ * @return boolean
201
+ */
202
+ public function isMoved()
203
+ {
204
+ return $this->moved;
205
+ }
206
+
207
+ /**
208
+ * @throws RuntimeException if is moved or not ok
209
+ */
210
+ private function validateActive()
211
+ {
212
+ if (false === $this->isOk()) {
213
+ throw new RuntimeException('Cannot retrieve stream due to upload error');
214
+ }
215
+
216
+ if ($this->isMoved()) {
217
+ throw new RuntimeException('Cannot retrieve stream after it has already been moved');
218
+ }
219
+ }
220
+
221
+ /**
222
+ * {@inheritdoc}
223
+ * @throws RuntimeException if the upload was not successful.
224
+ */
225
+ public function getStream()
226
+ {
227
+ $this->validateActive();
228
+
229
+ if ($this->stream instanceof StreamInterface) {
230
+ return $this->stream;
231
+ }
232
+
233
+ return new LazyOpenStream($this->file, 'r+');
234
+ }
235
+
236
+ /**
237
+ * {@inheritdoc}
238
+ *
239
+ * @see http://php.net/is_uploaded_file
240
+ * @see http://php.net/move_uploaded_file
241
+ * @param string $targetPath Path to which to move the uploaded file.
242
+ * @throws RuntimeException if the upload was not successful.
243
+ * @throws InvalidArgumentException if the $path specified is invalid.
244
+ * @throws RuntimeException on any error during the move operation, or on
245
+ * the second or subsequent call to the method.
246
+ */
247
+ public function moveTo($targetPath)
248
+ {
249
+ $this->validateActive();
250
+
251
+ if (false === $this->isStringNotEmpty($targetPath)) {
252
+ throw new InvalidArgumentException(
253
+ 'Invalid path provided for move operation; must be a non-empty string'
254
+ );
255
+ }
256
+
257
+ if ($this->file) {
258
+ $this->moved = php_sapi_name() == 'cli'
259
+ ? rename($this->file, $targetPath)
260
+ : move_uploaded_file($this->file, $targetPath);
261
+ } else {
262
+ copy_to_stream(
263
+ $this->getStream(),
264
+ new LazyOpenStream($targetPath, 'w')
265
+ );
266
+
267
+ $this->moved = true;
268
+ }
269
+
270
+ if (false === $this->moved) {
271
+ throw new RuntimeException(
272
+ sprintf('Uploaded file could not be moved to %s', $targetPath)
273
+ );
274
+ }
275
+ }
276
+
277
+ /**
278
+ * {@inheritdoc}
279
+ *
280
+ * @return int|null The file size in bytes or null if unknown.
281
+ */
282
+ public function getSize()
283
+ {
284
+ return $this->size;
285
+ }
286
+
287
+ /**
288
+ * {@inheritdoc}
289
+ *
290
+ * @see http://php.net/manual/en/features.file-upload.errors.php
291
+ * @return int One of PHP's UPLOAD_ERR_XXX constants.
292
+ */
293
+ public function getError()
294
+ {
295
+ return $this->error;
296
+ }
297
+
298
+ /**
299
+ * {@inheritdoc}
300
+ *
301
+ * @return string|null The filename sent by the client or null if none
302
+ * was provided.
303
+ */
304
+ public function getClientFilename()
305
+ {
306
+ return $this->clientFilename;
307
+ }
308
+
309
+ /**
310
+ * {@inheritdoc}
311
+ */
312
+ public function getClientMediaType()
313
+ {
314
+ return $this->clientMediaType;
315
+ }
316
+ }
lib/Azure/GuzzleHttp/Psr7/Uri.php ADDED
@@ -0,0 +1,602 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\UriInterface;
5
+
6
+ /**
7
+ * PSR-7 URI implementation.
8
+ *
9
+ * @author Michael Dowling
10
+ * @author Tobias Schultze
11
+ * @author Matthew Weier O'Phinney
12
+ */
13
+ class Uri implements UriInterface
14
+ {
15
+ private static $schemes = [
16
+ 'http' => 80,
17
+ 'https' => 443,
18
+ ];
19
+
20
+ private static $charUnreserved = 'a-zA-Z0-9_\-\.~';
21
+ private static $charSubDelims = '!\$&\'\(\)\*\+,;=';
22
+ private static $replaceQuery = ['=' => '%3D', '&' => '%26'];
23
+
24
+ /** @var string Uri scheme. */
25
+ private $scheme = '';
26
+
27
+ /** @var string Uri user info. */
28
+ private $userInfo = '';
29
+
30
+ /** @var string Uri host. */
31
+ private $host = '';
32
+
33
+ /** @var int|null Uri port. */
34
+ private $port;
35
+
36
+ /** @var string Uri path. */
37
+ private $path = '';
38
+
39
+ /** @var string Uri query string. */
40
+ private $query = '';
41
+
42
+ /** @var string Uri fragment. */
43
+ private $fragment = '';
44
+
45
+ /**
46
+ * @param string $uri URI to parse
47
+ */
48
+ public function __construct($uri = '')
49
+ {
50
+ if ($uri != '') {
51
+ $parts = parse_url($uri);
52
+ if ($parts === false) {
53
+ throw new \InvalidArgumentException("Unable to parse URI: $uri");
54
+ }
55
+ $this->applyParts($parts);
56
+ }
57
+ }
58
+
59
+ public function __toString()
60
+ {
61
+ return self::createUriString(
62
+ $this->scheme,
63
+ $this->getAuthority(),
64
+ $this->path,
65
+ $this->query,
66
+ $this->fragment
67
+ );
68
+ }
69
+
70
+ /**
71
+ * Removes dot segments from a path and returns the new path.
72
+ *
73
+ * @param string $path
74
+ *
75
+ * @return string
76
+ * @link http://tools.ietf.org/html/rfc3986#section-5.2.4
77
+ */
78
+ public static function removeDotSegments($path)
79
+ {
80
+ static $noopPaths = ['' => true, '/' => true, '*' => true];
81
+ static $ignoreSegments = ['.' => true, '..' => true];
82
+
83
+ if (isset($noopPaths[$path])) {
84
+ return $path;
85
+ }
86
+
87
+ $results = [];
88
+ $segments = explode('/', $path);
89
+ foreach ($segments as $segment) {
90
+ if ($segment === '..') {
91
+ array_pop($results);
92
+ } elseif (!isset($ignoreSegments[$segment])) {
93
+ $results[] = $segment;
94
+ }
95
+ }
96
+
97
+ $newPath = implode('/', $results);
98
+ // Add the leading slash if necessary
99
+ if (substr($path, 0, 1) === '/' &&
100
+ substr($newPath, 0, 1) !== '/'
101
+ ) {
102
+ $newPath = '/' . $newPath;
103
+ }
104
+
105
+ // Add the trailing slash if necessary
106
+ if ($newPath !== '/' && isset($ignoreSegments[end($segments)])) {
107
+ $newPath .= '/';
108
+ }
109
+
110
+ return $newPath;
111
+ }
112
+
113
+ /**
114
+ * Resolve a base URI with a relative URI and return a new URI.
115
+ *
116
+ * @param UriInterface $base Base URI
117
+ * @param string|UriInterface $rel Relative URI
118
+ *
119
+ * @return UriInterface
120
+ * @link http://tools.ietf.org/html/rfc3986#section-5.2
121
+ */
122
+ public static function resolve(UriInterface $base, $rel)
123
+ {
124
+ if (!($rel instanceof UriInterface)) {
125
+ $rel = new self($rel);
126
+ }
127
+
128
+ if ((string) $rel === '') {
129
+ // we can simply return the same base URI instance for this same-document reference
130
+ return $base;
131
+ }
132
+
133
+ if ($rel->getScheme() != '') {
134
+ return $rel->withPath(self::removeDotSegments($rel->getPath()));
135
+ }
136
+
137
+ if ($rel->getAuthority() != '') {
138
+ $targetAuthority = $rel->getAuthority();
139
+ $targetPath = self::removeDotSegments($rel->getPath());
140
+ $targetQuery = $rel->getQuery();
141
+ } else {
142
+ $targetAuthority = $base->getAuthority();
143
+ if ($rel->getPath() === '') {
144
+ $targetPath = $base->getPath();
145
+ $targetQuery = $rel->getQuery() != '' ? $rel->getQuery() : $base->getQuery();
146
+ } else {
147
+ if ($rel->getPath()[0] === '/') {
148
+ $targetPath = $rel->getPath();
149
+ } else {
150
+ if ($targetAuthority != '' && $base->getPath() === '') {
151
+ $targetPath = '/' . $rel->getPath();
152
+ } else {
153
+ $lastSlashPos = strrpos($base->getPath(), '/');
154
+ if ($lastSlashPos === false) {
155
+ $targetPath = $rel->getPath();
156
+ } else {
157
+ $targetPath = substr($base->getPath(), 0, $lastSlashPos + 1) . $rel->getPath();
158
+ }
159
+ }
160
+ }
161
+ $targetPath = self::removeDotSegments($targetPath);
162
+ $targetQuery = $rel->getQuery();
163
+ }
164
+ }
165
+
166
+ return new self(self::createUriString(
167
+ $base->getScheme(),
168
+ $targetAuthority,
169
+ $targetPath,
170
+ $targetQuery,
171
+ $rel->getFragment()
172
+ ));
173
+ }
174
+
175
+ /**
176
+ * Create a new URI with a specific query string value removed.
177
+ *
178
+ * Any existing query string values that exactly match the provided key are
179
+ * removed.
180
+ *
181
+ * @param UriInterface $uri URI to use as a base.
182
+ * @param string $key Query string key to remove.
183
+ *
184
+ * @return UriInterface
185
+ */
186
+ public static function withoutQueryValue(UriInterface $uri, $key)
187
+ {
188
+ $current = $uri->getQuery();
189
+ if ($current == '') {
190
+ return $uri;
191
+ }
192
+
193
+ $decodedKey = rawurldecode($key);
194
+ $result = array_filter(explode('&', $current), function ($part) use ($decodedKey) {
195
+ return rawurldecode(explode('=', $part)[0]) !== $decodedKey;
196
+ });
197
+
198
+ return $uri->withQuery(implode('&', $result));
199
+ }
200
+
201
+ /**
202
+ * Create a new URI with a specific query string value.
203
+ *
204
+ * Any existing query string values that exactly match the provided key are
205
+ * removed and replaced with the given key value pair.
206
+ *
207
+ * A value of null will set the query string key without a value, e.g. "key"
208
+ * instead of "key=value".
209
+ *
210
+ * @param UriInterface $uri URI to use as a base.
211
+ * @param string $key Key to set.
212
+ * @param string|null $value Value to set
213
+ *
214
+ * @return UriInterface
215
+ */
216
+ public static function withQueryValue(UriInterface $uri, $key, $value)
217
+ {
218
+ $current = $uri->getQuery();
219
+
220
+ if ($current == '') {
221
+ $result = [];
222
+ } else {
223
+ $decodedKey = rawurldecode($key);
224
+ $result = array_filter(explode('&', $current), function ($part) use ($decodedKey) {
225
+ return rawurldecode(explode('=', $part)[0]) !== $decodedKey;
226
+ });
227
+ }
228
+
229
+ // Query string separators ("=", "&") within the key or value need to be encoded
230
+ // (while preventing double-encoding) before setting the query string. All other
231
+ // chars that need percent-encoding will be encoded by withQuery().
232
+ $key = strtr($key, self::$replaceQuery);
233
+
234
+ if ($value !== null) {
235
+ $result[] = $key . '=' . strtr($value, self::$replaceQuery);
236
+ } else {
237
+ $result[] = $key;
238
+ }
239
+
240
+ return $uri->withQuery(implode('&', $result));
241
+ }
242
+
243
+ /**
244
+ * Create a URI from a hash of parse_url parts.
245
+ *
246
+ * @param array $parts
247
+ *
248
+ * @return self
249
+ */
250
+ public static function fromParts(array $parts)
251
+ {
252
+ $uri = new self();
253
+ $uri->applyParts($parts);
254
+ return $uri;
255
+ }
256
+
257
+ public function getScheme()
258
+ {
259
+ return $this->scheme;
260
+ }
261
+
262
+ public function getAuthority()
263
+ {
264
+ if ($this->host == '') {
265
+ return '';
266
+ }
267
+
268
+ $authority = $this->host;
269
+ if ($this->userInfo != '') {
270
+ $authority = $this->userInfo . '@' . $authority;
271
+ }
272
+
273
+ if ($this->port !== null) {
274
+ $authority .= ':' . $this->port;
275
+ }
276
+
277
+ return $authority;
278
+ }
279
+
280
+ public function getUserInfo()
281
+ {
282
+ return $this->userInfo;
283
+ }
284
+
285
+ public function getHost()
286
+ {
287
+ return $this->host;
288
+ }
289
+
290
+ public function getPort()
291
+ {
292
+ return $this->port;
293
+ }
294
+
295
+ public function getPath()
296
+ {
297
+ return $this->path;
298
+ }
299
+
300
+ public function getQuery()
301
+ {
302
+ return $this->query;
303
+ }
304
+
305
+ public function getFragment()
306
+ {
307
+ return $this->fragment;
308
+ }
309
+
310
+ public function withScheme($scheme)
311
+ {
312
+ $scheme = $this->filterScheme($scheme);
313
+
314
+ if ($this->scheme === $scheme) {
315
+ return $this;
316
+ }
317
+
318
+ $new = clone $this;
319
+ $new->scheme = $scheme;
320
+ $new->port = $new->filterPort($new->port);
321
+ return $new;
322
+ }
323
+
324
+ public function withUserInfo($user, $password = null)
325
+ {
326
+ $info = $user;
327
+ if ($password != '') {
328
+ $info .= ':' . $password;
329
+ }
330
+
331
+ if ($this->userInfo === $info) {
332
+ return $this;
333
+ }
334
+
335
+ $new = clone $this;
336
+ $new->userInfo = $info;
337
+ return $new;
338
+ }
339
+
340
+ public function withHost($host)
341
+ {
342
+ $host = $this->filterHost($host);
343
+
344
+ if ($this->host === $host) {
345
+ return $this;
346
+ }
347
+
348
+ $new = clone $this;
349
+ $new->host = $host;
350
+ return $new;
351
+ }
352
+
353
+ public function withPort($port)
354
+ {
355
+ $port = $this->filterPort($port);
356
+
357
+ if ($this->port === $port) {
358
+ return $this;
359
+ }
360
+
361
+ $new = clone $this;
362
+ $new->port = $port;
363
+ return $new;
364
+ }
365
+
366
+ public function withPath($path)
367
+ {
368
+ $path = $this->filterPath($path);
369
+
370
+ if ($this->path === $path) {
371
+ return $this;
372
+ }
373
+
374
+ $new = clone $this;
375
+ $new->path = $path;
376
+ return $new;
377
+ }
378
+
379
+ public function withQuery($query)
380
+ {
381
+ $query = $this->filterQueryAndFragment($query);
382
+
383
+ if ($this->query === $query) {
384
+ return $this;
385
+ }
386
+
387
+ $new = clone $this;
388
+ $new->query = $query;
389
+ return $new;
390
+ }
391
+
392
+ public function withFragment($fragment)
393
+ {
394
+ $fragment = $this->filterQueryAndFragment($fragment);
395
+
396
+ if ($this->fragment === $fragment) {
397
+ return $this;
398
+ }
399
+
400
+ $new = clone $this;
401
+ $new->fragment = $fragment;
402
+ return $new;
403
+ }
404
+
405
+ /**
406
+ * Apply parse_url parts to a URI.
407
+ *
408
+ * @param array $parts Array of parse_url parts to apply.
409
+ */
410
+ private function applyParts(array $parts)
411
+ {
412
+ $this->scheme = isset($parts['scheme'])
413
+ ? $this->filterScheme($parts['scheme'])
414
+ : '';
415
+ $this->userInfo = isset($parts['user']) ? $parts['user'] : '';
416
+ $this->host = isset($parts['host'])
417
+ ? $this->filterHost($parts['host'])
418
+ : '';
419
+ $this->port = isset($parts['port'])
420
+ ? $this->filterPort($parts['port'])
421
+ : null;
422
+ $this->path = isset($parts['path'])
423
+ ? $this->filterPath($parts['path'])
424
+ : '';
425
+ $this->query = isset($parts['query'])
426
+ ? $this->filterQueryAndFragment($parts['query'])
427
+ : '';
428
+ $this->fragment = isset($parts['fragment'])
429
+ ? $this->filterQueryAndFragment($parts['fragment'])
430
+ : '';
431
+ if (isset($parts['pass'])) {
432
+ $this->userInfo .= ':' . $parts['pass'];
433
+ }
434
+ }
435
+
436
+ /**
437
+ * Create a URI string from its various parts
438
+ *
439
+ * @param string $scheme
440
+ * @param string $authority
441
+ * @param string $path
442
+ * @param string $query
443
+ * @param string $fragment
444
+ * @return string
445
+ */
446
+ private static function createUriString($scheme, $authority, $path, $query, $fragment)
447
+ {
448
+ $uri = '';
449
+
450
+ if ($scheme != '') {
451
+ $uri .= $scheme . ':';
452
+ }
453
+
454
+ if ($authority != '') {
455
+ $uri .= '//' . $authority;
456
+ }
457
+
458
+ if ($path != '') {
459
+ if ($path[0] !== '/') {
460
+ if ($authority != '') {
461
+ // If the path is rootless and an authority is present, the path MUST be prefixed by "/"
462
+ $path = '/' . $path;
463
+ }
464
+ } elseif (isset($path[1]) && $path[1] === '/') {
465
+ if ($authority == '') {
466
+ // If the path is starting with more than one "/" and no authority is present, the
467
+ // starting slashes MUST be reduced to one.
468
+ $path = '/' . ltrim($path, '/');
469
+ }
470
+ }
471
+
472
+ $uri .= $path;
473
+ }
474
+
475
+ if ($query != '') {
476
+ $uri .= '?' . $query;
477
+ }
478
+
479
+ if ($fragment != '') {
480
+ $uri .= '#' . $fragment;
481
+ }
482
+
483
+ return $uri;
484
+ }
485
+
486
+ /**
487
+ * Is a given port non-standard for the current scheme?
488
+ *
489
+ * @param string $scheme
490
+ * @param int $port
491
+ *
492
+ * @return bool
493
+ */
494
+ private static function isNonStandardPort($scheme, $port)
495
+ {
496
+ return !isset(self::$schemes[$scheme]) || $port !== self::$schemes[$scheme];
497
+ }
498
+
499
+ /**
500
+ * @param string $scheme
501
+ *
502
+ * @return string
503
+ *
504
+ * @throws \InvalidArgumentException If the scheme is invalid.
505
+ */
506
+ private function filterScheme($scheme)
507
+ {
508
+ if (!is_string($scheme)) {
509
+ throw new \InvalidArgumentException('Scheme must be a string');
510
+ }
511
+
512
+ return strtolower($scheme);
513
+ }
514
+
515
+ /**
516
+ * @param string $host
517
+ *
518
+ * @return string
519
+ *
520
+ * @throws \InvalidArgumentException If the host is invalid.
521
+ */
522
+ private function filterHost($host)
523
+ {
524
+ if (!is_string($host)) {
525
+ throw new \InvalidArgumentException('Host must be a string');
526
+ }
527
+
528
+ return strtolower($host);
529
+ }
530
+
531
+ /**
532
+ * @param int|null $port
533
+ *
534
+ * @return int|null
535
+ *
536
+ * @throws \InvalidArgumentException If the port is invalid.
537
+ */
538
+ private function filterPort($port)
539
+ {
540
+ if ($port === null) {
541
+ return null;
542
+ }
543
+
544
+ $port = (int) $port;
545
+ if (1 > $port || 0xffff < $port) {
546
+ throw new \InvalidArgumentException(
547
+ sprintf('Invalid port: %d. Must be between 1 and 65535', $port)
548
+ );
549
+ }
550
+
551
+ return self::isNonStandardPort($this->scheme, $port) ? $port : null;
552
+ }
553
+
554
+ /**
555
+ * Filters the path of a URI
556
+ *
557
+ * @param string $path
558
+ *
559
+ * @return string
560
+ *
561
+ * @throws \InvalidArgumentException If the path is invalid.
562
+ */
563
+ private function filterPath($path)
564
+ {
565
+ if (!is_string($path)) {
566
+ throw new \InvalidArgumentException('Path must be a string');
567
+ }
568
+
569
+ return preg_replace_callback(
570
+ '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/]++|%(?![A-Fa-f0-9]{2}))/',
571
+ [$this, 'rawurlencodeMatchZero'],
572
+ $path
573
+ );
574
+ }
575
+
576
+ /**
577
+ * Filters the query string or fragment of a URI.
578
+ *
579
+ * @param string $str
580
+ *
581
+ * @return string
582
+ *
583
+ * @throws \InvalidArgumentException If the query or fragment is invalid.
584
+ */
585
+ private function filterQueryAndFragment($str)
586
+ {
587
+ if (!is_string($str)) {
588
+ throw new \InvalidArgumentException('Query and fragment must be a string');
589
+ }
590
+
591
+ return preg_replace_callback(
592
+ '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/',
593
+ [$this, 'rawurlencodeMatchZero'],
594
+ $str
595
+ );
596
+ }
597
+
598
+ private function rawurlencodeMatchZero(array $match)
599
+ {
600
+ return rawurlencode($match[0]);
601
+ }
602
+ }
lib/Azure/GuzzleHttp/Psr7/functions.php ADDED
@@ -0,0 +1,826 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Psr7;
3
+
4
+ use Psr\Http\Message\MessageInterface;
5
+ use Psr\Http\Message\RequestInterface;
6
+ use Psr\Http\Message\ResponseInterface;
7
+ use Psr\Http\Message\ServerRequestInterface;
8
+ use Psr\Http\Message\StreamInterface;
9
+ use Psr\Http\Message\UriInterface;
10
+
11
+ /**
12
+ * Returns the string representation of an HTTP message.
13
+ *
14
+ * @param MessageInterface $message Message to convert to a string.
15
+ *
16
+ * @return string
17
+ */
18
+ function str(MessageInterface $message)
19
+ {
20
+ if ($message instanceof RequestInterface) {
21
+ $msg = trim($message->getMethod() . ' '
22
+ . $message->getRequestTarget())
23
+ . ' HTTP/' . $message->getProtocolVersion();
24
+ if (!$message->hasHeader('host')) {
25
+ $msg .= "\r\nHost: " . $message->getUri()->getHost();
26
+ }
27
+ } elseif ($message instanceof ResponseInterface) {
28
+ $msg = 'HTTP/' . $message->getProtocolVersion() . ' '
29
+ . $message->getStatusCode() . ' '
30
+ . $message->getReasonPhrase();
31
+ } else {
32
+ throw new \InvalidArgumentException('Unknown message type');
33
+ }
34
+
35
+ foreach ($message->getHeaders() as $name => $values) {
36
+ $msg .= "\r\n{$name}: " . implode(', ', $values);
37
+ }
38
+
39
+ return "{$msg}\r\n\r\n" . $message->getBody();
40
+ }
41
+
42
+ /**
43
+ * Returns a UriInterface for the given value.
44
+ *
45
+ * This function accepts a string or {@see Psr\Http\Message\UriInterface} and
46
+ * returns a UriInterface for the given value. If the value is already a
47
+ * `UriInterface`, it is returned as-is.
48
+ *
49
+ * @param string|UriInterface $uri
50
+ *
51
+ * @return UriInterface
52
+ * @throws \InvalidArgumentException
53
+ */
54
+ function uri_for($uri)
55
+ {
56
+ if ($uri instanceof UriInterface) {
57
+ return $uri;
58
+ } elseif (is_string($uri)) {
59
+ return new Uri($uri);
60
+ }
61
+
62
+ throw new \InvalidArgumentException('URI must be a string or UriInterface');
63
+ }
64
+
65
+ /**
66
+ * Create a new stream based on the input type.
67
+ *
68
+ * Options is an associative array that can contain the following keys:
69
+ * - metadata: Array of custom metadata.
70
+ * - size: Size of the stream.
71
+ *
72
+ * @param resource|string|null|int|float|bool|StreamInterface|callable $resource Entity body data
73
+ * @param array $options Additional options
74
+ *
75
+ * @return Stream
76
+ * @throws \InvalidArgumentException if the $resource arg is not valid.
77
+ */
78
+ function stream_for($resource = '', array $options = [])
79
+ {
80
+ if (is_scalar($resource)) {
81
+ $stream = fopen('php://temp', 'r+');
82
+ if ($resource !== '') {
83
+ fwrite($stream, $resource);
84
+ fseek($stream, 0);
85
+ }
86
+ return new Stream($stream, $options);
87
+ }
88
+
89
+ switch (gettype($resource)) {
90
+ case 'resource':
91
+ return new Stream($resource, $options);
92
+ case 'object':
93
+ if ($resource instanceof StreamInterface) {
94
+ return $resource;
95
+ } elseif ($resource instanceof \Iterator) {
96
+ return new PumpStream(function () use ($resource) {
97
+ if (!$resource->valid()) {
98
+ return false;
99
+ }
100
+ $result = $resource->current();
101
+ $resource->next();
102
+ return $result;
103
+ }, $options);
104
+ } elseif (method_exists($resource, '__toString')) {
105
+ return stream_for((string) $resource, $options);
106
+ }
107
+ break;
108
+ case 'NULL':
109
+ return new Stream(fopen('php://temp', 'r+'), $options);
110
+ }
111
+
112
+ if (is_callable($resource)) {
113
+ return new PumpStream($resource, $options);
114
+ }
115
+
116
+ throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource));
117
+ }
118
+
119
+ /**
120
+ * Parse an array of header values containing ";" separated data into an
121
+ * array of associative arrays representing the header key value pair
122
+ * data of the header. When a parameter does not contain a value, but just
123
+ * contains a key, this function will inject a key with a '' string value.
124
+ *
125
+ * @param string|array $header Header to parse into components.
126
+ *
127
+ * @return array Returns the parsed header values.
128
+ */
129
+ function parse_header($header)
130
+ {
131
+ static $trimmed = "\"' \n\t\r";
132
+ $params = $matches = [];
133
+
134
+ foreach (normalize_header($header) as $val) {
135
+ $part = [];
136
+ foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
137
+ if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
138
+ $m = $matches[0];
139
+ if (isset($m[1])) {
140
+ $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
141
+ } else {
142
+ $part[] = trim($m[0], $trimmed);
143
+ }
144
+ }
145
+ }
146
+ if ($part) {
147
+ $params[] = $part;
148
+ }
149
+ }
150
+
151
+ return $params;
152
+ }
153
+
154
+ /**
155
+ * Converts an array of header values that may contain comma separated
156
+ * headers into an array of headers with no comma separated values.
157
+ *
158
+ * @param string|array $header Header to normalize.
159
+ *
160
+ * @return array Returns the normalized header field values.
161
+ */
162
+ function normalize_header($header)
163
+ {
164
+ if (!is_array($header)) {
165
+ return array_map('trim', explode(',', $header));
166
+ }
167
+
168
+ $result = [];
169
+ foreach ($header as $value) {
170
+ foreach ((array) $value as $v) {
171
+ if (strpos($v, ',') === false) {
172
+ $result[] = $v;
173
+ continue;
174
+ }
175
+ foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $v) as $vv) {
176
+ $result[] = trim($vv);
177
+ }
178
+ }
179
+ }
180
+
181
+ return $result;
182
+ }
183
+
184
+ /**
185
+ * Clone and modify a request with the given changes.
186
+ *
187
+ * The changes can be one of:
188
+ * - method: (string) Changes the HTTP method.
189
+ * - set_headers: (array) Sets the given headers.
190
+ * - remove_headers: (array) Remove the given headers.
191
+ * - body: (mixed) Sets the given body.
192
+ * - uri: (UriInterface) Set the URI.
193
+ * - query: (string) Set the query string value of the URI.
194
+ * - version: (string) Set the protocol version.
195
+ *
196
+ * @param RequestInterface $request Request to clone and modify.
197
+ * @param array $changes Changes to apply.
198
+ *
199
+ * @return RequestInterface
200
+ */
201
+ function modify_request(RequestInterface $request, array $changes)
202
+ {
203
+ if (!$changes) {
204
+ return $request;
205
+ }
206
+
207
+ $headers = $request->getHeaders();
208
+
209
+ if (!isset($changes['uri'])) {
210
+ $uri = $request->getUri();
211
+ } else {
212
+ // Remove the host header if one is on the URI
213
+ if ($host = $changes['uri']->getHost()) {
214
+ $changes['set_headers']['Host'] = $host;
215
+
216
+ if ($port = $changes['uri']->getPort()) {
217
+ $standardPorts = ['http' => 80, 'https' => 443];
218
+ $scheme = $changes['uri']->getScheme();
219
+ if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) {
220
+ $changes['set_headers']['Host'] .= ':'.$port;
221
+ }
222
+ }
223
+ }
224
+ $uri = $changes['uri'];
225
+ }
226
+
227
+ if (!empty($changes['remove_headers'])) {
228
+ $headers = _caseless_remove($changes['remove_headers'], $headers);
229
+ }
230
+
231
+ if (!empty($changes['set_headers'])) {
232
+ $headers = _caseless_remove(array_keys($changes['set_headers']), $headers);
233
+ $headers = $changes['set_headers'] + $headers;
234
+ }
235
+
236
+ if (isset($changes['query'])) {
237
+ $uri = $uri->withQuery($changes['query']);
238
+ }
239
+
240
+ if ($request instanceof ServerRequestInterface) {
241
+ return new ServerRequest(
242
+ isset($changes['method']) ? $changes['method'] : $request->getMethod(),
243
+ $uri,
244
+ $headers,
245
+ isset($changes['body']) ? $changes['body'] : $request->getBody(),
246
+ isset($changes['version'])
247
+ ? $changes['version']
248
+ : $request->getProtocolVersion(),
249
+ $request->getServerParams()
250
+ );
251
+ }
252
+
253
+ return new Request(
254
+ isset($changes['method']) ? $changes['method'] : $request->getMethod(),
255
+ $uri,
256
+ $headers,
257
+ isset($changes['body']) ? $changes['body'] : $request->getBody(),
258
+ isset($changes['version'])
259
+ ? $changes['version']
260
+ : $request->getProtocolVersion()
261
+ );
262
+ }
263
+
264
+ /**
265
+ * Attempts to rewind a message body and throws an exception on failure.
266
+ *
267
+ * The body of the message will only be rewound if a call to `tell()` returns a
268
+ * value other than `0`.
269
+ *
270
+ * @param MessageInterface $message Message to rewind
271
+ *
272
+ * @throws \RuntimeException
273
+ */
274
+ function rewind_body(MessageInterface $message)
275
+ {
276
+ $body = $message->getBody();
277
+
278
+ if ($body->tell()) {
279
+ $body->rewind();
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Safely opens a PHP stream resource using a filename.
285
+ *
286
+ * When fopen fails, PHP normally raises a warning. This function adds an
287
+ * error handler that checks for errors and throws an exception instead.
288
+ *
289
+ * @param string $filename File to open
290
+ * @param string $mode Mode used to open the file
291
+ *
292
+ * @return resource
293
+ * @throws \RuntimeException if the file cannot be opened
294
+ */
295
+ function try_fopen($filename, $mode)
296
+ {
297
+ $ex = null;
298
+ set_error_handler(function () use ($filename, $mode, &$ex) {
299
+ $ex = new \RuntimeException(sprintf(
300
+ 'Unable to open %s using mode %s: %s',
301
+ $filename,
302
+ $mode,
303
+ func_get_args()[1]
304
+ ));
305
+ });
306
+
307
+ $handle = fopen($filename, $mode);
308
+ restore_error_handler();
309
+
310
+ if ($ex) {
311
+ /** @var $ex \RuntimeException */
312
+ throw $ex;
313
+ }
314
+
315
+ return $handle;
316
+ }
317
+
318
+ /**
319
+ * Copy the contents of a stream into a string until the given number of
320
+ * bytes have been read.
321
+ *
322
+ * @param StreamInterface $stream Stream to read
323
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
324
+ * to read the entire stream.
325
+ * @return string
326
+ * @throws \RuntimeException on error.
327
+ */
328
+ function copy_to_string(StreamInterface $stream, $maxLen = -1)
329
+ {
330
+ $buffer = '';
331
+
332
+ if ($maxLen === -1) {
333
+ while (!$stream->eof()) {
334
+ $buf = $stream->read(1048576);
335
+ // Using a loose equality here to match on '' and false.
336
+ if ($buf == null) {
337
+ break;
338
+ }
339
+ $buffer .= $buf;
340
+ }
341
+ return $buffer;
342
+ }
343
+
344
+ $len = 0;
345
+ while (!$stream->eof() && $len < $maxLen) {
346
+ $buf = $stream->read($maxLen - $len);
347
+ // Using a loose equality here to match on '' and false.
348
+ if ($buf == null) {
349
+ break;
350
+ }
351
+ $buffer .= $buf;
352
+ $len = strlen($buffer);
353
+ }
354
+
355
+ return $buffer;
356
+ }
357
+
358
+ /**
359
+ * Copy the contents of a stream into another stream until the given number
360
+ * of bytes have been read.
361
+ *
362
+ * @param StreamInterface $source Stream to read from
363
+ * @param StreamInterface $dest Stream to write to
364
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
365
+ * to read the entire stream.
366
+ *
367
+ * @throws \RuntimeException on error.
368
+ */
369
+ function copy_to_stream(
370
+ StreamInterface $source,
371
+ StreamInterface $dest,
372
+ $maxLen = -1
373
+ ) {
374
+ if ($maxLen === -1) {
375
+ while (!$source->eof()) {
376
+ if (!$dest->write($source->read(1048576))) {
377
+ break;
378
+ }
379
+ }
380
+ return;
381
+ }
382
+
383
+ $bytes = 0;
384
+ while (!$source->eof()) {
385
+ $buf = $source->read($maxLen - $bytes);
386
+ if (!($len = strlen($buf))) {
387
+ break;
388
+ }
389
+ $bytes += $len;
390
+ $dest->write($buf);
391
+ if ($bytes == $maxLen) {
392
+ break;
393
+ }
394
+ }
395
+ }
396
+
397
+ /**
398
+ * Calculate a hash of a Stream
399
+ *
400
+ * @param StreamInterface $stream Stream to calculate the hash for
401
+ * @param string $algo Hash algorithm (e.g. md5, crc32, etc)
402
+ * @param bool $rawOutput Whether or not to use raw output
403
+ *
404
+ * @return string Returns the hash of the stream
405
+ * @throws \RuntimeException on error.
406
+ */
407
+ function hash(
408
+ StreamInterface $stream,
409
+ $algo,
410
+ $rawOutput = false
411
+ ) {
412
+ $pos = $stream->tell();
413
+
414
+ if ($pos > 0) {
415
+ $stream->rewind();
416
+ }
417
+
418
+ $ctx = hash_init($algo);
419
+ while (!$stream->eof()) {
420
+ hash_update($ctx, $stream->read(1048576));
421
+ }
422
+
423
+ $out = hash_final($ctx, (bool) $rawOutput);
424
+ $stream->seek($pos);
425
+
426
+ return $out;
427
+ }
428
+
429
+ /**
430
+ * Read a line from the stream up to the maximum allowed buffer length
431
+ *
432
+ * @param StreamInterface $stream Stream to read from
433
+ * @param int $maxLength Maximum buffer length
434
+ *
435
+ * @return string|bool
436
+ */
437
+ function readline(StreamInterface $stream, $maxLength = null)
438
+ {
439
+ $buffer = '';
440
+ $size = 0;
441
+
442
+ while (!$stream->eof()) {
443
+ // Using a loose equality here to match on '' and false.
444
+ if (null == ($byte = $stream->read(1))) {
445
+ return $buffer;
446
+ }
447
+ $buffer .= $byte;
448
+ // Break when a new line is found or the max length - 1 is reached
449
+ if ($byte === "\n" || ++$size === $maxLength - 1) {
450
+ break;
451
+ }
452
+ }
453
+
454
+ return $buffer;
455
+ }
456
+
457
+ /**
458
+ * Parses a request message string into a request object.
459
+ *
460
+ * @param string $message Request message string.
461
+ *
462
+ * @return Request
463
+ */
464
+ function parse_request($message)
465
+ {
466
+ $data = _parse_message($message);
467
+ $matches = [];
468
+ if (!preg_match('/^[\S]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) {
469
+ throw new \InvalidArgumentException('Invalid request string');
470
+ }
471
+ $parts = explode(' ', $data['start-line'], 3);
472
+ $version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1';
473
+
474
+ $request = new Request(
475
+ $parts[0],
476
+ $matches[1] === '/' ? _parse_request_uri($parts[1], $data['headers']) : $parts[1],
477
+ $data['headers'],
478
+ $data['body'],
479
+ $version
480
+ );
481
+
482
+ return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]);
483
+ }
484
+
485
+ /**
486
+ * Parses a response message string into a response object.
487
+ *
488
+ * @param string $message Response message string.
489
+ *
490
+ * @return Response
491
+ */
492
+ function parse_response($message)
493
+ {
494
+ $data = _parse_message($message);
495
+ if (!preg_match('/^HTTP\/.* [0-9]{3} .*/', $data['start-line'])) {
496
+ throw new \InvalidArgumentException('Invalid response string');
497
+ }
498
+ $parts = explode(' ', $data['start-line'], 3);
499
+
500
+ return new Response(
501
+ $parts[1],
502
+ $data['headers'],
503
+ $data['body'],
504
+ explode('/', $parts[0])[1],
505
+ isset($parts[2]) ? $parts[2] : null
506
+ );
507
+ }
508
+
509
+ /**
510
+ * Parse a query string into an associative array.
511
+ *
512
+ * If multiple values are found for the same key, the value of that key
513
+ * value pair will become an array. This function does not parse nested
514
+ * PHP style arrays into an associative array (e.g., foo[a]=1&foo[b]=2 will
515
+ * be parsed into ['foo[a]' => '1', 'foo[b]' => '2']).
516
+ *
517
+ * @param string $str Query string to parse
518
+ * @param bool|string $urlEncoding How the query string is encoded
519
+ *
520
+ * @return array
521
+ */
522
+ function parse_query($str, $urlEncoding = true)
523
+ {
524
+ $result = [];
525
+
526
+ if ($str === '') {
527
+ return $result;
528
+ }
529
+
530
+ if ($urlEncoding === true) {
531
+ $decoder = function ($value) {
532
+ return rawurldecode(str_replace('+', ' ', $value));
533
+ };
534
+ } elseif ($urlEncoding == PHP_QUERY_RFC3986) {
535
+ $decoder = 'rawurldecode';
536
+ } elseif ($urlEncoding == PHP_QUERY_RFC1738) {
537
+ $decoder = 'urldecode';
538
+ } else {
539
+ $decoder = function ($str) { return $str; };
540
+ }
541
+
542
+ foreach (explode('&', $str) as $kvp) {
543
+ $parts = explode('=', $kvp, 2);
544
+ $key = $decoder($parts[0]);
545
+ $value = isset($parts[1]) ? $decoder($parts[1]) : null;
546
+ if (!isset($result[$key])) {
547
+ $result[$key] = $value;
548
+ } else {
549
+ if (!is_array($result[$key])) {
550
+ $result[$key] = [$result[$key]];
551
+ }
552
+ $result[$key][] = $value;
553
+ }
554
+ }
555
+
556
+ return $result;
557
+ }
558
+
559
+ /**
560
+ * Build a query string from an array of key value pairs.
561
+ *
562
+ * This function can use the return value of parse_query() to build a query
563
+ * string. This function does not modify the provided keys when an array is
564
+ * encountered (like http_build_query would).
565
+ *
566
+ * @param array $params Query string parameters.
567
+ * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
568
+ * to encode using RFC3986, or PHP_QUERY_RFC1738
569
+ * to encode using RFC1738.
570
+ * @return string
571
+ */
572
+ function build_query(array $params, $encoding = PHP_QUERY_RFC3986)
573
+ {
574
+ if (!$params) {
575
+ return '';
576
+ }
577
+
578
+ if ($encoding === false) {
579
+ $encoder = function ($str) { return $str; };
580
+ } elseif ($encoding === PHP_QUERY_RFC3986) {
581
+ $encoder = 'rawurlencode';
582
+ } elseif ($encoding === PHP_QUERY_RFC1738) {
583
+ $encoder = 'urlencode';
584
+ } else {
585
+ throw new \InvalidArgumentException('Invalid type');
586
+ }
587
+
588
+ $qs = '';
589
+ foreach ($params as $k => $v) {
590
+ $k = $encoder($k);
591
+ if (!is_array($v)) {
592
+ $qs .= $k;
593
+ if ($v !== null) {
594
+ $qs .= '=' . $encoder($v);
595
+ }
596
+ $qs .= '&';
597
+ } else {
598
+ foreach ($v as $vv) {
599
+ $qs .= $k;
600
+ if ($vv !== null) {
601
+ $qs .= '=' . $encoder($vv);
602
+ }
603
+ $qs .= '&';
604
+ }
605
+ }
606
+ }
607
+
608
+ return $qs ? (string) substr($qs, 0, -1) : '';
609
+ }
610
+
611
+ /**
612
+ * Determines the mimetype of a file by looking at its extension.
613
+ *
614
+ * @param $filename
615
+ *
616
+ * @return null|string
617
+ */
618
+ function mimetype_from_filename($filename)
619
+ {
620
+ return mimetype_from_extension(pathinfo($filename, PATHINFO_EXTENSION));
621
+ }
622
+
623
+ /**
624
+ * Maps a file extensions to a mimetype.
625
+ *
626
+ * @param $extension string The file extension.
627
+ *
628
+ * @return string|null
629
+ * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types
630
+ */
631
+ function mimetype_from_extension($extension)
632
+ {
633
+ static $mimetypes = [
634
+ '7z' => 'application/x-7z-compressed',
635
+ 'aac' => 'audio/x-aac',
636
+ 'ai' => 'application/postscript',
637
+ 'aif' => 'audio/x-aiff',
638
+ 'asc' => 'text/plain',
639
+ 'asf' => 'video/x-ms-asf',
640
+ 'atom' => 'application/atom+xml',
641
+ 'avi' => 'video/x-msvideo',
642
+ 'bmp' => 'image/bmp',
643
+ 'bz2' => 'application/x-bzip2',
644
+ 'cer' => 'application/pkix-cert',
645
+ 'crl' => 'application/pkix-crl',
646
+ 'crt' => 'application/x-x509-ca-cert',
647
+ 'css' => 'text/css',
648
+ 'csv' => 'text/csv',
649
+ 'cu' => 'application/cu-seeme',
650
+ 'deb' => 'application/x-debian-package',
651
+ 'doc' => 'application/msword',
652
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
653
+ 'dvi' => 'application/x-dvi',
654
+ 'eot' => 'application/vnd.ms-fontobject',
655
+ 'eps' => 'application/postscript',
656
+ 'epub' => 'application/epub+zip',
657
+ 'etx' => 'text/x-setext',
658
+ 'flac' => 'audio/flac',
659
+ 'flv' => 'video/x-flv',
660
+ 'gif' => 'image/gif',
661
+ 'gz' => 'application/gzip',
662
+ 'htm' => 'text/html',
663
+ 'html' => 'text/html',
664
+ 'ico' => 'image/x-icon',
665
+ 'ics' => 'text/calendar',
666
+ 'ini' => 'text/plain',
667
+ 'iso' => 'application/x-iso9660-image',
668
+ 'jar' => 'application/java-archive',
669
+ 'jpe' => 'image/jpeg',
670
+ 'jpeg' => 'image/jpeg',
671
+ 'jpg' => 'image/jpeg',
672
+ 'js' => 'text/javascript',
673
+ 'json' => 'application/json',
674
+ 'latex' => 'application/x-latex',
675
+ 'log' => 'text/plain',
676
+ 'm4a' => 'audio/mp4',
677
+ 'm4v' => 'video/mp4',
678
+ 'mid' => 'audio/midi',
679
+ 'midi' => 'audio/midi',
680
+ 'mov' => 'video/quicktime',
681
+ 'mp3' => 'audio/mpeg',
682
+ 'mp4' => 'video/mp4',
683
+ 'mp4a' => 'audio/mp4',
684
+ 'mp4v' => 'video/mp4',
685
+ 'mpe' => 'video/mpeg',
686
+ 'mpeg' => 'video/mpeg',
687
+ 'mpg' => 'video/mpeg',
688
+ 'mpg4' => 'video/mp4',
689
+ 'oga' => 'audio/ogg',
690
+ 'ogg' => 'audio/ogg',
691
+ 'ogv' => 'video/ogg',
692
+ 'ogx' => 'application/ogg',
693
+ 'pbm' => 'image/x-portable-bitmap',
694
+ 'pdf' => 'application/pdf',
695
+ 'pgm' => 'image/x-portable-graymap',
696
+ 'png' => 'image/png',
697
+ 'pnm' => 'image/x-portable-anymap',
698
+ 'ppm' => 'image/x-portable-pixmap',
699
+ 'ppt' => 'application/vnd.ms-powerpoint',
700
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
701
+ 'ps' => 'application/postscript',
702
+ 'qt' => 'video/quicktime',
703
+ 'rar' => 'application/x-rar-compressed',
704
+ 'ras' => 'image/x-cmu-raster',
705
+ 'rss' => 'application/rss+xml',
706
+ 'rtf' => 'application/rtf',
707
+ 'sgm' => 'text/sgml',
708
+ 'sgml' => 'text/sgml',
709
+ 'svg' => 'image/svg+xml',
710
+ 'swf' => 'application/x-shockwave-flash',
711
+ 'tar' => 'application/x-tar',
712
+ 'tif' => 'image/tiff',
713
+ 'tiff' => 'image/tiff',
714
+ 'torrent' => 'application/x-bittorrent',
715
+ 'ttf' => 'application/x-font-ttf',
716
+ 'txt' => 'text/plain',
717
+ 'wav' => 'audio/x-wav',
718
+ 'webm' => 'video/webm',
719
+ 'wma' => 'audio/x-ms-wma',
720
+ 'wmv' => 'video/x-ms-wmv',
721
+ 'woff' => 'application/x-font-woff',
722
+ 'wsdl' => 'application/wsdl+xml',
723
+ 'xbm' => 'image/x-xbitmap',
724
+ 'xls' => 'application/vnd.ms-excel',
725
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
726
+ 'xml' => 'application/xml',
727
+ 'xpm' => 'image/x-xpixmap',
728
+ 'xwd' => 'image/x-xwindowdump',
729
+ 'yaml' => 'text/yaml',
730
+ 'yml' => 'text/yaml',
731
+ 'zip' => 'application/zip',
732
+ ];
733
+
734
+ $extension = strtolower($extension);
735
+
736
+ return isset($mimetypes[$extension])
737
+ ? $mimetypes[$extension]
738
+ : null;
739
+ }
740
+
741
+ /**
742
+ * Parses an HTTP message into an associative array.
743
+ *
744
+ * The array contains the "start-line" key containing the start line of
745
+ * the message, "headers" key containing an associative array of header
746
+ * array values, and a "body" key containing the body of the message.
747
+ *
748
+ * @param string $message HTTP request or response to parse.
749
+ *
750
+ * @return array
751
+ * @internal
752
+ */
753
+ function _parse_message($message)
754
+ {
755
+ if (!$message) {
756
+ throw new \InvalidArgumentException('Invalid message');
757
+ }
758
+
759
+ // Iterate over each line in the message, accounting for line endings
760
+ $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
761
+ $result = ['start-line' => array_shift($lines), 'headers' => [], 'body' => ''];
762
+ array_shift($lines);
763
+
764
+ for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) {
765
+ $line = $lines[$i];
766
+ // If two line breaks were encountered, then this is the end of body
767
+ if (empty($line)) {
768
+ if ($i < $totalLines - 1) {
769
+ $result['body'] = implode('', array_slice($lines, $i + 2));
770
+ }
771
+ break;
772
+ }
773
+ if (strpos($line, ':')) {
774
+ $parts = explode(':', $line, 2);
775
+ $key = trim($parts[0]);
776
+ $value = isset($parts[1]) ? trim($parts[1]) : '';
777
+ $result['headers'][$key][] = $value;
778
+ }
779
+ }
780
+
781
+ return $result;
782
+ }
783
+
784
+ /**
785
+ * Constructs a URI for an HTTP request message.
786
+ *
787
+ * @param string $path Path from the start-line
788
+ * @param array $headers Array of headers (each value an array).
789
+ *
790
+ * @return string
791
+ * @internal
792
+ */
793
+ function _parse_request_uri($path, array $headers)
794
+ {
795
+ $hostKey = array_filter(array_keys($headers), function ($k) {
796
+ return strtolower($k) === 'host';
797
+ });
798
+
799
+ // If no host is found, then a full URI cannot be constructed.
800
+ if (!$hostKey) {
801
+ return $path;
802
+ }
803
+
804
+ $host = $headers[reset($hostKey)][0];
805
+ $scheme = substr($host, -4) === ':443' ? 'https' : 'http';
806
+
807
+ return $scheme . '://' . $host . '/' . ltrim($path, '/');
808
+ }
809
+
810
+ /** @internal */
811
+ function _caseless_remove($keys, array $data)
812
+ {
813
+ $result = [];
814
+
815
+ foreach ($keys as &$key) {
816
+ $key = strtolower($key);
817
+ }
818
+
819
+ foreach ($data as $k => $v) {
820
+ if (!in_array(strtolower($k), $keys)) {
821
+ $result[$k] = $v;
822
+ }
823
+ }
824
+
825
+ return $result;
826
+ }
lib/Azure/GuzzleHttp/Psr7/functions_include.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Don't redefine the functions if included multiple times.
4
+ if (!function_exists('GuzzleHttp\Psr7\str')) {
5
+ require __DIR__ . '/functions.php';
6
+ }
lib/Azure/GuzzleHttp/RedirectMiddleware.php ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Exception\BadResponseException;
5
+ use GuzzleHttp\Exception\TooManyRedirectsException;
6
+ use GuzzleHttp\Promise\PromiseInterface;
7
+ use GuzzleHttp\Psr7;
8
+ use Psr\Http\Message\RequestInterface;
9
+ use Psr\Http\Message\ResponseInterface;
10
+ use Psr\Http\Message\UriInterface;
11
+
12
+ /**
13
+ * Request redirect middleware.
14
+ *
15
+ * Apply this middleware like other middleware using
16
+ * {@see GuzzleHttp\Middleware::redirect()}.
17
+ */
18
+ class RedirectMiddleware
19
+ {
20
+ const HISTORY_HEADER = 'X-Guzzle-Redirect-History';
21
+
22
+ public static $defaultSettings = [
23
+ 'max' => 5,
24
+ 'protocols' => ['http', 'https'],
25
+ 'strict' => false,
26
+ 'referer' => false,
27
+ 'track_redirects' => false,
28
+ ];
29
+
30
+ /** @var callable */
31
+ private $nextHandler;
32
+
33
+ /**
34
+ * @param callable $nextHandler Next handler to invoke.
35
+ */
36
+ public function __construct(callable $nextHandler)
37
+ {
38
+ $this->nextHandler = $nextHandler;
39
+ }
40
+
41
+ /**
42
+ * @param RequestInterface $request
43
+ * @param array $options
44
+ *
45
+ * @return PromiseInterface
46
+ */
47
+ public function __invoke(RequestInterface $request, array $options)
48
+ {
49
+ $fn = $this->nextHandler;
50
+
51
+ if (empty($options['allow_redirects'])) {
52
+ return $fn($request, $options);
53
+ }
54
+
55
+ if ($options['allow_redirects'] === true) {
56
+ $options['allow_redirects'] = self::$defaultSettings;
57
+ } elseif (!is_array($options['allow_redirects'])) {
58
+ throw new \InvalidArgumentException('allow_redirects must be true, false, or array');
59
+ } else {
60
+ // Merge the default settings with the provided settings
61
+ $options['allow_redirects'] += self::$defaultSettings;
62
+ }
63
+
64
+ if (empty($options['allow_redirects']['max'])) {
65
+ return $fn($request, $options);
66
+ }
67
+
68
+ return $fn($request, $options)
69
+ ->then(function (ResponseInterface $response) use ($request, $options) {
70
+ return $this->checkRedirect($request, $options, $response);
71
+ });
72
+ }
73
+
74
+ /**
75
+ * @param RequestInterface $request
76
+ * @param array $options
77
+ * @param ResponseInterface|PromiseInterface $response
78
+ *
79
+ * @return ResponseInterface|PromiseInterface
80
+ */
81
+ public function checkRedirect(
82
+ RequestInterface $request,
83
+ array $options,
84
+ ResponseInterface $response
85
+ ) {
86
+ if (substr($response->getStatusCode(), 0, 1) != '3'
87
+ || !$response->hasHeader('Location')
88
+ ) {
89
+ return $response;
90
+ }
91
+
92
+ $this->guardMax($request, $options);
93
+ $nextRequest = $this->modifyRequest($request, $options, $response);
94
+
95
+ if (isset($options['allow_redirects']['on_redirect'])) {
96
+ call_user_func(
97
+ $options['allow_redirects']['on_redirect'],
98
+ $request,
99
+ $response,
100
+ $nextRequest->getUri()
101
+ );
102
+ }
103
+
104
+ /** @var PromiseInterface|ResponseInterface $promise */
105
+ $promise = $this($nextRequest, $options);
106
+
107
+ // Add headers to be able to track history of redirects.
108
+ if (!empty($options['allow_redirects']['track_redirects'])) {
109
+ return $this->withTracking(
110
+ $promise,
111
+ (string) $nextRequest->getUri()
112
+ );
113
+ }
114
+
115
+ return $promise;
116
+ }
117
+
118
+ private function withTracking(PromiseInterface $promise, $uri)
119
+ {
120
+ return $promise->then(
121
+ function (ResponseInterface $response) use ($uri) {
122
+ // Note that we are pushing to the front of the list as this
123
+ // would be an earlier response than what is currently present
124
+ // in the history header.
125
+ $header = $response->getHeader(self::HISTORY_HEADER);
126
+ array_unshift($header, $uri);
127
+ return $response->withHeader(self::HISTORY_HEADER, $header);
128
+ }
129
+ );
130
+ }
131
+
132
+ private function guardMax(RequestInterface $request, array &$options)
133
+ {
134
+ $current = isset($options['__redirect_count'])
135
+ ? $options['__redirect_count']
136
+ : 0;
137
+ $options['__redirect_count'] = $current + 1;
138
+ $max = $options['allow_redirects']['max'];
139
+
140
+ if ($options['__redirect_count'] > $max) {
141
+ throw new TooManyRedirectsException(
142
+ "Will not follow more than {$max} redirects",
143
+ $request
144
+ );
145
+ }
146
+ }
147
+
148
+ /**
149
+ * @param RequestInterface $request
150
+ * @param array $options
151
+ * @param ResponseInterface $response
152
+ *
153
+ * @return RequestInterface
154
+ */
155
+ public function modifyRequest(
156
+ RequestInterface $request,
157
+ array $options,
158
+ ResponseInterface $response
159
+ ) {
160
+ // Request modifications to apply.
161
+ $modify = [];
162
+ $protocols = $options['allow_redirects']['protocols'];
163
+
164
+ // Use a GET request if this is an entity enclosing request and we are
165
+ // not forcing RFC compliance, but rather emulating what all browsers
166
+ // would do.
167
+ $statusCode = $response->getStatusCode();
168
+ if ($statusCode == 303 ||
169
+ ($statusCode <= 302 && $request->getBody() && !$options['allow_redirects']['strict'])
170
+ ) {
171
+ $modify['method'] = 'GET';
172
+ $modify['body'] = '';
173
+ }
174
+
175
+ $modify['uri'] = $this->redirectUri($request, $response, $protocols);
176
+ Psr7\rewind_body($request);
177
+
178
+ // Add the Referer header if it is told to do so and only
179
+ // add the header if we are not redirecting from https to http.
180
+ if ($options['allow_redirects']['referer']
181
+ && $modify['uri']->getScheme() === $request->getUri()->getScheme()
182
+ ) {
183
+ $uri = $request->getUri()->withUserInfo('', '');
184
+ $modify['set_headers']['Referer'] = (string) $uri;
185
+ } else {
186
+ $modify['remove_headers'][] = 'Referer';
187
+ }
188
+
189
+ // Remove Authorization header if host is different.
190
+ if ($request->getUri()->getHost() !== $modify['uri']->getHost()) {
191
+ $modify['remove_headers'][] = 'Authorization';
192
+ }
193
+
194
+ return Psr7\modify_request($request, $modify);
195
+ }
196
+
197
+ /**
198
+ * Set the appropriate URL on the request based on the location header
199
+ *
200
+ * @param RequestInterface $request
201
+ * @param ResponseInterface $response
202
+ * @param array $protocols
203
+ *
204
+ * @return UriInterface
205
+ */
206
+ private function redirectUri(
207
+ RequestInterface $request,
208
+ ResponseInterface $response,
209
+ array $protocols
210
+ ) {
211
+ $location = Psr7\Uri::resolve(
212
+ $request->getUri(),
213
+ $response->getHeaderLine('Location')
214
+ );
215
+
216
+ // Ensure that the redirect URI is allowed based on the protocols.
217
+ if (!in_array($location->getScheme(), $protocols)) {
218
+ throw new BadResponseException(
219
+ sprintf(
220
+ 'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',
221
+ $location,
222
+ implode(', ', $protocols)
223
+ ),
224
+ $request,
225
+ $response
226
+ );
227
+ }
228
+
229
+ return $location;
230
+ }
231
+ }
lib/Azure/GuzzleHttp/RequestOptions.php ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * This class contains a list of built-in Guzzle request options.
6
+ *
7
+ * More documentation for each option can be found at http://guzzlephp.org/.
8
+ *
9
+ * @link http://docs.guzzlephp.org/en/v6/request-options.html
10
+ */
11
+ final class RequestOptions
12
+ {
13
+ /**
14
+ * allow_redirects: (bool|array) Controls redirect behavior. Pass false
15
+ * to disable redirects, pass true to enable redirects, pass an
16
+ * associative to provide custom redirect settings. Defaults to "false".
17
+ * This option only works if your handler has the RedirectMiddleware. When
18
+ * passing an associative array, you can provide the following key value
19
+ * pairs:
20
+ *
21
+ * - max: (int, default=5) maximum number of allowed redirects.
22
+ * - strict: (bool, default=false) Set to true to use strict redirects
23
+ * meaning redirect POST requests with POST requests vs. doing what most
24
+ * browsers do which is redirect POST requests with GET requests
25
+ * - referer: (bool, default=true) Set to false to disable the Referer
26
+ * header.
27
+ * - protocols: (array, default=['http', 'https']) Allowed redirect
28
+ * protocols.
29
+ * - on_redirect: (callable) PHP callable that is invoked when a redirect
30
+ * is encountered. The callable is invoked with the request, the redirect
31
+ * response that was received, and the effective URI. Any return value
32
+ * from the on_redirect function is ignored.
33
+ */
34
+ const ALLOW_REDIRECTS = 'allow_redirects';
35
+
36
+ /**
37
+ * auth: (array) Pass an array of HTTP authentication parameters to use
38
+ * with the request. The array must contain the username in index [0],
39
+ * the password in index [1], and you can optionally provide a built-in
40
+ * authentication type in index [2]. Pass null to disable authentication
41
+ * for a request.
42
+ */
43
+ const AUTH = 'auth';
44
+
45
+ /**
46
+ * body: (string|null|callable|iterator|object) Body to send in the
47
+ * request.
48
+ */
49
+ const BODY = 'body';
50
+
51
+ /**
52
+ * cert: (string|array) Set to a string to specify the path to a file
53
+ * containing a PEM formatted SSL client side certificate. If a password
54
+ * is required, then set cert to an array containing the path to the PEM
55
+ * file in the first array element followed by the certificate password
56
+ * in the second array element.
57
+ */
58
+ const CERT = 'cert';
59
+
60
+ /**
61
+ * cookies: (bool|GuzzleHttp\Cookie\CookieJarInterface, default=false)
62
+ * Specifies whether or not cookies are used in a request or what cookie
63
+ * jar to use or what cookies to send. This option only works if your
64
+ * handler has the `cookie` middleware. Valid values are `false` and
65
+ * an instance of {@see GuzzleHttp\Cookie\CookieJarInterface}.
66
+ */
67
+ const COOKIES = 'cookies';
68
+
69
+ /**
70
+ * connect_timeout: (float, default=0) Float describing the number of
71
+ * seconds to wait while trying to connect to a server. Use 0 to wait
72
+ * indefinitely (the default behavior).
73
+ */
74
+ const CONNECT_TIMEOUT = 'connect_timeout';
75
+
76
+ /**
77
+ * debug: (bool|resource) Set to true or set to a PHP stream returned by
78
+ * fopen() enable debug output with the HTTP handler used to send a
79
+ * request.
80
+ */
81
+ const DEBUG = 'debug';
82
+
83
+ /**
84
+ * decode_content: (bool, default=true) Specify whether or not
85
+ * Content-Encoding responses (gzip, deflate, etc.) are automatically
86
+ * decoded.
87
+ */
88
+ const DECODE_CONTENT = 'decode_content';
89
+
90
+ /**
91
+ * delay: (int) The amount of time to delay before sending in milliseconds.
92
+ */
93
+ const DELAY = 'delay';
94
+
95
+ /**
96
+ * expect: (bool|integer) Controls the behavior of the
97
+ * "Expect: 100-Continue" header.
98
+ *
99
+ * Set to `true` to enable the "Expect: 100-Continue" header for all
100
+ * requests that sends a body. Set to `false` to disable the
101
+ * "Expect: 100-Continue" header for all requests. Set to a number so that
102
+ * the size of the payload must be greater than the number in order to send
103
+ * the Expect header. Setting to a number will send the Expect header for
104
+ * all requests in which the size of the payload cannot be determined or
105
+ * where the body is not rewindable.
106
+ *
107
+ * By default, Guzzle will add the "Expect: 100-Continue" header when the
108
+ * size of the body of a request is greater than 1 MB and a request is
109
+ * using HTTP/1.1.
110
+ */
111
+ const EXPECT = 'expect';
112
+
113
+ /**
114
+ * form_params: (array) Associative array of form field names to values
115
+ * where each value is a string or array of strings. Sets the Content-Type
116
+ * header to application/x-www-form-urlencoded when no Content-Type header
117
+ * is already present.
118
+ */
119
+ const FORM_PARAMS = 'form_params';
120
+
121
+ /**
122
+ * headers: (array) Associative array of HTTP headers. Each value MUST be
123
+ * a string or array of strings.
124
+ */
125
+ const HEADERS = 'headers';
126
+
127
+ /**
128
+ * http_errors: (bool, default=true) Set to false to disable exceptions
129
+ * when a non- successful HTTP response is received. By default,
130
+ * exceptions will be thrown for 4xx and 5xx responses. This option only
131
+ * works if your handler has the `httpErrors` middleware.
132
+ */
133
+ const HTTP_ERRORS = 'http_errors';
134
+
135
+ /**
136
+ * json: (mixed) Adds JSON data to a request. The provided value is JSON
137
+ * encoded and a Content-Type header of application/json will be added to
138
+ * the request if no Content-Type header is already present.
139
+ */
140
+ const JSON = 'json';
141
+
142
+ /**
143
+ * multipart: (array) Array of associative arrays, each containing a
144
+ * required "name" key mapping to the form field, name, a required
145
+ * "contents" key mapping to a StreamInterface|resource|string, an
146
+ * optional "headers" associative array of custom headers, and an
147
+ * optional "filename" key mapping to a string to send as the filename in
148
+ * the part. If no "filename" key is present, then no "filename" attribute
149
+ * will be added to the part.
150
+ */
151
+ const MULTIPART = 'multipart';
152
+
153
+ /**
154
+ * on_headers: (callable) A callable that is invoked when the HTTP headers
155
+ * of the response have been received but the body has not yet begun to
156
+ * download.
157
+ */
158
+ const ON_HEADERS = 'on_headers';
159
+
160
+ /**
161
+ * on_stats: (callable) allows you to get access to transfer statistics of
162
+ * a request and access the lower level transfer details of the handler
163
+ * associated with your client. ``on_stats`` is a callable that is invoked
164
+ * when a handler has finished sending a request. The callback is invoked
165
+ * with transfer statistics about the request, the response received, or
166
+ * the error encountered. Included in the data is the total amount of time
167
+ * taken to send the request.
168
+ */
169
+ const ON_STATS = 'on_stats';
170
+
171
+ /**
172
+ * progress: (callable) Defines a function to invoke when transfer
173
+ * progress is made. The function accepts the following positional
174
+ * arguments: the total number of bytes expected to be downloaded, the
175
+ * number of bytes downloaded so far, the number of bytes expected to be
176
+ * uploaded, the number of bytes uploaded so far.
177
+ */
178
+ const PROGRESS = 'progress';
179
+
180
+ /**
181
+ * proxy: (string|array) Pass a string to specify an HTTP proxy, or an
182
+ * array to specify different proxies for different protocols (where the
183
+ * key is the protocol and the value is a proxy string).
184
+ */
185
+ const PROXY = 'proxy';
186
+
187
+ /**
188
+ * query: (array|string) Associative array of query string values to add
189
+ * to the request. This option uses PHP's http_build_query() to create
190
+ * the string representation. Pass a string value if you need more
191
+ * control than what this method provides
192
+ */
193
+ const QUERY = 'query';
194
+
195
+ /**
196
+ * sink: (resource|string|StreamInterface) Where the data of the
197
+ * response is written to. Defaults to a PHP temp stream. Providing a
198
+ * string will write data to a file by the given name.
199
+ */
200
+ const SINK = 'sink';
201
+
202
+ /**
203
+ * synchronous: (bool) Set to true to inform HTTP handlers that you intend
204
+ * on waiting on the response. This can be useful for optimizations. Note
205
+ * that a promise is still returned if you are using one of the async
206
+ * client methods.
207
+ */
208
+ const SYNCHRONOUS = 'synchronous';
209
+
210
+ /**
211
+ * ssl_key: (array|string) Specify the path to a file containing a private
212
+ * SSL key in PEM format. If a password is required, then set to an array
213
+ * containing the path to the SSL key in the first array element followed
214
+ * by the password required for the certificate in the second element.
215
+ */
216
+ const SSL_KEY = 'ssl_key';
217
+
218
+ /**
219
+ * stream: Set to true to attempt to stream a response rather than
220
+ * download it all up-front.
221
+ */
222
+ const STREAM = 'stream';
223
+
224
+ /**
225
+ * verify: (bool|string, default=true) Describes the SSL certificate
226
+ * verification behavior of a request. Set to true to enable SSL
227
+ * certificate verification using the system CA bundle when available
228
+ * (the default). Set to false to disable certificate verification (this
229
+ * is insecure!). Set to a string to provide the path to a CA bundle on
230
+ * disk to enable verification using a custom certificate.
231
+ */
232
+ const VERIFY = 'verify';
233
+
234
+ /**
235
+ * timeout: (float, default=0) Float describing the timeout of the
236
+ * request in seconds. Use 0 to wait indefinitely (the default behavior).
237
+ */
238
+ const TIMEOUT = 'timeout';
239
+
240
+ /**
241
+ * version: (float) Specifies the HTTP protocol version to attempt to use.
242
+ */
243
+ const VERSION = 'version';
244
+ }
lib/Azure/GuzzleHttp/RetryMiddleware.php ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Promise\PromiseInterface;
5
+ use GuzzleHttp\Promise\RejectedPromise;
6
+ use GuzzleHttp\Psr7;
7
+ use Psr\Http\Message\RequestInterface;
8
+ use Psr\Http\Message\ResponseInterface;
9
+
10
+ /**
11
+ * Middleware that retries requests based on the boolean result of
12
+ * invoking the provided "decider" function.
13
+ */
14
+ class RetryMiddleware
15
+ {
16
+ /** @var callable */
17
+ private $nextHandler;
18
+
19
+ /** @var callable */
20
+ private $decider;
21
+
22
+ /**
23
+ * @param callable $decider Function that accepts the number of retries,
24
+ * a request, [response], and [exception] and
25
+ * returns true if the request is to be
26
+ * retried.
27
+ * @param callable $nextHandler Next handler to invoke.
28
+ * @param callable $delay Function that accepts the number of retries
29
+ * and [response] and returns the number of
30
+ * milliseconds to delay.
31
+ */
32
+ public function __construct(
33
+ callable $decider,
34
+ callable $nextHandler,
35
+ callable $delay = null
36
+ ) {
37
+ $this->decider = $decider;
38
+ $this->nextHandler = $nextHandler;
39
+ $this->delay = $delay ?: __CLASS__ . '::exponentialDelay';
40
+ }
41
+
42
+ /**
43
+ * Default exponential backoff delay function.
44
+ *
45
+ * @param $retries
46
+ *
47
+ * @return int
48
+ */
49
+ public static function exponentialDelay($retries)
50
+ {
51
+ return (int) pow(2, $retries - 1);
52
+ }
53
+
54
+ /**
55
+ * @param RequestInterface $request
56
+ * @param array $options
57
+ *
58
+ * @return PromiseInterface
59
+ */
60
+ public function __invoke(RequestInterface $request, array $options)
61
+ {
62
+ if (!isset($options['retries'])) {
63
+ $options['retries'] = 0;
64
+ }
65
+
66
+ $fn = $this->nextHandler;
67
+ return $fn($request, $options)
68
+ ->then(
69
+ $this->onFulfilled($request, $options),
70
+ $this->onRejected($request, $options)
71
+ );
72
+ }
73
+
74
+ private function onFulfilled(RequestInterface $req, array $options)
75
+ {
76
+ return function ($value) use ($req, $options) {
77
+ if (!call_user_func(
78
+ $this->decider,
79
+ $options['retries'],
80
+ $req,
81
+ $value,
82
+ null
83
+ )) {
84
+ return $value;
85
+ }
86
+ return $this->doRetry($req, $options, $value);
87
+ };
88
+ }
89
+
90
+ private function onRejected(RequestInterface $req, array $options)
91
+ {
92
+ return function ($reason) use ($req, $options) {
93
+ if (!call_user_func(
94
+ $this->decider,
95
+ $options['retries'],
96
+ $req,
97
+ null,
98
+ $reason
99
+ )) {
100
+ return new RejectedPromise($reason);
101
+ }
102
+ return $this->doRetry($req, $options);
103
+ };
104
+ }
105
+
106
+ private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null)
107
+ {
108
+ $options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);
109
+
110
+ return $this($request, $options);
111
+ }
112
+ }
lib/Azure/GuzzleHttp/TransferStats.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use Psr\Http\Message\RequestInterface;
5
+ use Psr\Http\Message\ResponseInterface;
6
+ use Psr\Http\Message\UriInterface;
7
+
8
+ /**
9
+ * Represents data at the point after it was transferred either successfully
10
+ * or after a network error.
11
+ */
12
+ final class TransferStats
13
+ {
14
+ private $request;
15
+ private $response;
16
+ private $transferTime;
17
+ private $handlerStats;
18
+ private $handlerErrorData;
19
+
20
+ /**
21
+ * @param RequestInterface $request Request that was sent.
22
+ * @param ResponseInterface $response Response received (if any)
23
+ * @param null $transferTime Total handler transfer time.
24
+ * @param mixed $handlerErrorData Handler error data.
25
+ * @param array $handlerStats Handler specific stats.
26
+ */
27
+ public function __construct(
28
+ RequestInterface $request,
29
+ ResponseInterface $response = null,
30
+ $transferTime = null,
31
+ $handlerErrorData = null,
32
+ $handlerStats = []
33
+ ) {
34
+ $this->request = $request;
35
+ $this->response = $response;
36
+ $this->transferTime = $transferTime;
37
+ $this->handlerErrorData = $handlerErrorData;
38
+ $this->handlerStats = $handlerStats;
39
+ }
40
+
41
+ /**
42
+ * @return RequestInterface
43
+ */
44
+ public function getRequest()
45
+ {
46
+ return $this->request;
47
+ }
48
+
49
+ /**
50
+ * Returns the response that was received (if any).
51
+ *
52
+ * @return ResponseInterface|null
53
+ */
54
+ public function getResponse()
55
+ {
56
+ return $this->response;
57
+ }
58
+
59
+ /**
60
+ * Returns true if a response was received.
61
+ *
62
+ * @return bool
63
+ */
64
+ public function hasResponse()
65
+ {
66
+ return $this->response !== null;
67
+ }
68
+
69
+ /**
70
+ * Gets handler specific error data.
71
+ *
72
+ * This might be an exception, a integer representing an error code, or
73
+ * anything else. Relying on this value assumes that you know what handler
74
+ * you are using.
75
+ *
76
+ * @return mixed
77
+ */
78
+ public function getHandlerErrorData()
79
+ {
80
+ return $this->handlerErrorData;
81
+ }
82
+
83
+ /**
84
+ * Get the effective URI the request was sent to.
85
+ *
86
+ * @return UriInterface
87
+ */
88
+ public function getEffectiveUri()
89
+ {
90
+ return $this->request->getUri();
91
+ }
92
+
93
+ /**
94
+ * Get the estimated time the request was being transferred by the handler.
95
+ *
96
+ * @return float Time in seconds.
97
+ */
98
+ public function getTransferTime()
99
+ {
100
+ return $this->transferTime;
101
+ }
102
+
103
+ /**
104
+ * Gets an array of all of the handler specific transfer data.
105
+ *
106
+ * @return array
107
+ */
108
+ public function getHandlerStats()
109
+ {
110
+ return $this->handlerStats;
111
+ }
112
+
113
+ /**
114
+ * Get a specific handler statistic from the handler by name.
115
+ *
116
+ * @param string $stat Handler specific transfer stat to retrieve.
117
+ *
118
+ * @return mixed|null
119
+ */
120
+ public function getHandlerStat($stat)
121
+ {
122
+ return isset($this->handlerStats[$stat])
123
+ ? $this->handlerStats[$stat]
124
+ : null;
125
+ }
126
+ }
lib/Azure/GuzzleHttp/UriTemplate.php ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Expands URI templates. Userland implementation of PECL uri_template.
6
+ *
7
+ * @link http://tools.ietf.org/html/rfc6570
8
+ */
9
+ class UriTemplate
10
+ {
11
+ /** @var string URI template */
12
+ private $template;
13
+
14
+ /** @var array Variables to use in the template expansion */
15
+ private $variables;
16
+
17
+ /** @var array Hash for quick operator lookups */
18
+ private static $operatorHash = [
19
+ '' => ['prefix' => '', 'joiner' => ',', 'query' => false],
20
+ '+' => ['prefix' => '', 'joiner' => ',', 'query' => false],
21
+ '#' => ['prefix' => '#', 'joiner' => ',', 'query' => false],
22
+ '.' => ['prefix' => '.', 'joiner' => '.', 'query' => false],
23
+ '/' => ['prefix' => '/', 'joiner' => '/', 'query' => false],
24
+ ';' => ['prefix' => ';', 'joiner' => ';', 'query' => true],
25
+ '?' => ['prefix' => '?', 'joiner' => '&', 'query' => true],
26
+ '&' => ['prefix' => '&', 'joiner' => '&', 'query' => true]
27
+ ];
28
+
29
+ /** @var array Delimiters */
30
+ private static $delims = [':', '/', '?', '#', '[', ']', '@', '!', '$',
31
+ '&', '\'', '(', ')', '*', '+', ',', ';', '='];
32
+
33
+ /** @var array Percent encoded delimiters */
34
+ private static $delimsPct = ['%3A', '%2F', '%3F', '%23', '%5B', '%5D',
35
+ '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C',
36
+ '%3B', '%3D'];
37
+
38
+ public function expand($template, array $variables)
39
+ {
40
+ if (false === strpos($template, '{')) {
41
+ return $template;
42
+ }
43
+
44
+ $this->template = $template;
45
+ $this->variables = $variables;
46
+
47
+ return preg_replace_callback(
48
+ '/\{([^\}]+)\}/',
49
+ [$this, 'expandMatch'],
50
+ $this->template
51
+ );
52
+ }
53
+
54
+ /**
55
+ * Parse an expression into parts
56
+ *
57
+ * @param string $expression Expression to parse
58
+ *
59
+ * @return array Returns an associative array of parts
60
+ */
61
+ private function parseExpression($expression)
62
+ {
63
+ $result = [];
64
+
65
+ if (isset(self::$operatorHash[$expression[0]])) {
66
+ $result['operator'] = $expression[0];
67
+ $expression = substr($expression, 1);
68
+ } else {
69
+ $result['operator'] = '';
70
+ }
71
+
72
+ foreach (explode(',', $expression) as $value) {
73
+ $value = trim($value);
74
+ $varspec = [];
75
+ if ($colonPos = strpos($value, ':')) {
76
+ $varspec['value'] = substr($value, 0, $colonPos);
77
+ $varspec['modifier'] = ':';
78
+ $varspec['position'] = (int) substr($value, $colonPos + 1);
79
+ } elseif (substr($value, -1) === '*') {
80
+ $varspec['modifier'] = '*';
81
+ $varspec['value'] = substr($value, 0, -1);
82
+ } else {
83
+ $varspec['value'] = (string) $value;
84
+ $varspec['modifier'] = '';
85
+ }
86
+ $result['values'][] = $varspec;
87
+ }
88
+
89
+ return $result;
90
+ }
91
+
92
+ /**
93
+ * Process an expansion
94
+ *
95
+ * @param array $matches Matches met in the preg_replace_callback
96
+ *
97
+ * @return string Returns the replacement string
98
+ */
99
+ private function expandMatch(array $matches)
100
+ {
101
+ static $rfc1738to3986 = ['+' => '%20', '%7e' => '~'];
102
+
103
+ $replacements = [];
104
+ $parsed = self::parseExpression($matches[1]);
105
+ $prefix = self::$operatorHash[$parsed['operator']]['prefix'];
106
+ $joiner = self::$operatorHash[$parsed['operator']]['joiner'];
107
+ $useQuery = self::$operatorHash[$parsed['operator']]['query'];
108
+
109
+ foreach ($parsed['values'] as $value) {
110
+
111
+ if (!isset($this->variables[$value['value']])) {
112
+ continue;
113
+ }
114
+
115
+ $variable = $this->variables[$value['value']];
116
+ $actuallyUseQuery = $useQuery;
117
+ $expanded = '';
118
+
119
+ if (is_array($variable)) {
120
+
121
+ $isAssoc = $this->isAssoc($variable);
122
+ $kvp = [];
123
+ foreach ($variable as $key => $var) {
124
+
125
+ if ($isAssoc) {
126
+ $key = rawurlencode($key);
127
+ $isNestedArray = is_array($var);
128
+ } else {
129
+ $isNestedArray = false;
130
+ }
131
+
132
+ if (!$isNestedArray) {
133
+ $var = rawurlencode($var);
134
+ if ($parsed['operator'] === '+' ||
135
+ $parsed['operator'] === '#'
136
+ ) {
137
+ $var = $this->decodeReserved($var);
138
+ }
139
+ }
140
+
141
+ if ($value['modifier'] === '*') {
142
+ if ($isAssoc) {
143
+ if ($isNestedArray) {
144
+ // Nested arrays must allow for deeply nested
145
+ // structures.
146
+ $var = strtr(
147
+ http_build_query([$key => $var]),
148
+ $rfc1738to3986
149
+ );
150
+ } else {
151
+ $var = $key . '=' . $var;
152
+ }
153
+ } elseif ($key > 0 && $actuallyUseQuery) {
154
+ $var = $value['value'] . '=' . $var;
155
+ }
156
+ }
157
+
158
+ $kvp[$key] = $var;
159
+ }
160
+
161
+ if (empty($variable)) {
162
+ $actuallyUseQuery = false;
163
+ } elseif ($value['modifier'] === '*') {
164
+ $expanded = implode($joiner, $kvp);
165
+ if ($isAssoc) {
166
+ // Don't prepend the value name when using the explode
167
+ // modifier with an associative array.
168
+ $actuallyUseQuery = false;
169
+ }
170
+ } else {
171
+ if ($isAssoc) {
172
+ // When an associative array is encountered and the
173
+ // explode modifier is not set, then the result must be
174
+ // a comma separated list of keys followed by their
175
+ // respective values.
176
+ foreach ($kvp as $k => &$v) {
177
+ $v = $k . ',' . $v;
178
+ }
179
+ }
180
+ $expanded = implode(',', $kvp);
181
+ }
182
+
183
+ } else {
184
+ if ($value['modifier'] === ':') {
185
+ $variable = substr($variable, 0, $value['position']);
186
+ }
187
+ $expanded = rawurlencode($variable);
188
+ if ($parsed['operator'] === '+' || $parsed['operator'] === '#') {
189
+ $expanded = $this->decodeReserved($expanded);
190
+ }
191
+ }
192
+
193
+ if ($actuallyUseQuery) {
194
+ if (!$expanded && $joiner !== '&') {
195
+ $expanded = $value['value'];
196
+ } else {
197
+ $expanded = $value['value'] . '=' . $expanded;
198
+ }
199
+ }
200
+
201
+ $replacements[] = $expanded;
202
+ }
203
+
204
+ $ret = implode($joiner, $replacements);
205
+ if ($ret && $prefix) {
206
+ return $prefix . $ret;
207
+ }
208
+
209
+ return $ret;
210
+ }
211
+
212
+ /**
213
+ * Determines if an array is associative.
214
+ *
215
+ * This makes the assumption that input arrays are sequences or hashes.
216
+ * This assumption is a tradeoff for accuracy in favor of speed, but it
217
+ * should work in almost every case where input is supplied for a URI
218
+ * template.
219
+ *
220
+ * @param array $array Array to check
221
+ *
222
+ * @return bool
223
+ */
224
+ private function isAssoc(array $array)
225
+ {
226
+ return $array && array_keys($array)[0] !== 0;
227
+ }
228
+
229
+ /**
230
+ * Removes percent encoding on reserved characters (used with + and #
231
+ * modifiers).
232
+ *
233
+ * @param string $string String to fix
234
+ *
235
+ * @return string
236
+ */
237
+ private function decodeReserved($string)
238
+ {
239
+ return str_replace(self::$delimsPct, self::$delims, $string);
240
+ }
241
+ }
lib/Azure/GuzzleHttp/functions.php ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Handler\CurlHandler;
5
+ use GuzzleHttp\Handler\CurlMultiHandler;
6
+ use GuzzleHttp\Handler\Proxy;
7
+ use GuzzleHttp\Handler\StreamHandler;
8
+
9
+ /**
10
+ * Expands a URI template
11
+ *
12
+ * @param string $template URI template
13
+ * @param array $variables Template variables
14
+ *
15
+ * @return string
16
+ */
17
+ function uri_template($template, array $variables)
18
+ {
19
+ if (extension_loaded('uri_template')) {
20
+ // @codeCoverageIgnoreStart
21
+ return \uri_template($template, $variables);
22
+ // @codeCoverageIgnoreEnd
23
+ }
24
+
25
+ static $uriTemplate;
26
+ if (!$uriTemplate) {
27
+ $uriTemplate = new UriTemplate();
28
+ }
29
+
30
+ return $uriTemplate->expand($template, $variables);
31
+ }
32
+
33
+ /**
34
+ * Debug function used to describe the provided value type and class.
35
+ *
36
+ * @param mixed $input
37
+ *
38
+ * @return string Returns a string containing the type of the variable and
39
+ * if a class is provided, the class name.
40
+ */
41
+ function describe_type($input)
42
+ {
43
+ switch (gettype($input)) {
44
+ case 'object':
45
+ return 'object(' . get_class($input) . ')';
46
+ case 'array':
47
+ return 'array(' . count($input) . ')';
48
+ default:
49
+ ob_start();
50
+ var_dump($input);
51
+ // normalize float vs double
52
+ return str_replace('double(', 'float(', rtrim(ob_get_clean()));
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Parses an array of header lines into an associative array of headers.
58
+ *
59
+ * @param array $lines Header lines array of strings in the following
60
+ * format: "Name: Value"
61
+ * @return array
62
+ */
63
+ function headers_from_lines($lines)
64
+ {
65
+ $headers = [];
66
+
67
+ foreach ($lines as $line) {
68
+ $parts = explode(':', $line, 2);
69
+ $headers[trim($parts[0])][] = isset($parts[1])
70
+ ? trim($parts[1])
71
+ : null;
72
+ }
73
+
74
+ return $headers;
75
+ }
76
+
77
+ /**
78
+ * Returns a debug stream based on the provided variable.
79
+ *
80
+ * @param mixed $value Optional value
81
+ *
82
+ * @return resource
83
+ */
84
+ function debug_resource($value = null)
85
+ {
86
+ if (is_resource($value)) {
87
+ return $value;
88
+ } elseif (defined('STDOUT')) {
89
+ return STDOUT;
90
+ }
91
+
92
+ return fopen('php://output', 'w');
93
+ }
94
+
95
+ /**
96
+ * Chooses and creates a default handler to use based on the environment.
97
+ *
98
+ * The returned handler is not wrapped by any default middlewares.
99
+ *
100
+ * @throws \RuntimeException if no viable Handler is available.
101
+ * @return callable Returns the best handler for the given system.
102
+ */
103
+ function choose_handler()
104
+ {
105
+ $handler = null;
106
+ if (function_exists('curl_multi_exec') && function_exists('curl_exec')) {
107
+ $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
108
+ } elseif (function_exists('curl_exec')) {
109
+ $handler = new CurlHandler();
110
+ } elseif (function_exists('curl_multi_exec')) {
111
+ $handler = new CurlMultiHandler();
112
+ }
113
+
114
+ if (ini_get('allow_url_fopen')) {
115
+ $handler = $handler
116
+ ? Proxy::wrapStreaming($handler, new StreamHandler())
117
+ : new StreamHandler();
118
+ } elseif (!$handler) {
119
+ throw new \RuntimeException('GuzzleHttp requires cURL, the '
120
+ . 'allow_url_fopen ini setting, or a custom HTTP handler.');
121
+ }
122
+
123
+ return $handler;
124
+ }
125
+
126
+ /**
127
+ * Get the default User-Agent string to use with Guzzle
128
+ *
129
+ * @return string
130
+ */
131
+ function default_user_agent()
132
+ {
133
+ static $defaultAgent = '';
134
+
135
+ if (!$defaultAgent) {
136
+ $defaultAgent = 'GuzzleHttp/' . Client::VERSION;
137
+ if (extension_loaded('curl') && function_exists('curl_version')) {
138
+ $defaultAgent .= ' curl/' . \curl_version()['version'];
139
+ }
140
+ $defaultAgent .= ' PHP/' . PHP_VERSION;
141
+ }
142
+
143
+ return $defaultAgent;
144
+ }
145
+
146
+ /**
147
+ * Returns the default cacert bundle for the current system.
148
+ *
149
+ * First, the openssl.cafile and curl.cainfo php.ini settings are checked.
150
+ * If those settings are not configured, then the common locations for
151
+ * bundles found on Red Hat, CentOS, Fedora, Ubuntu, Debian, FreeBSD, OS X
152
+ * and Windows are checked. If any of these file locations are found on
153
+ * disk, they will be utilized.
154
+ *
155
+ * Note: the result of this function is cached for subsequent calls.
156
+ *
157
+ * @return string
158
+ * @throws \RuntimeException if no bundle can be found.
159
+ */
160
+ function default_ca_bundle()
161
+ {
162
+ static $cached = null;
163
+ static $cafiles = [
164
+ // Red Hat, CentOS, Fedora (provided by the ca-certificates package)
165
+ '/etc/pki/tls/certs/ca-bundle.crt',
166
+ // Ubuntu, Debian (provided by the ca-certificates package)
167
+ '/etc/ssl/certs/ca-certificates.crt',
168
+ // FreeBSD (provided by the ca_root_nss package)
169
+ '/usr/local/share/certs/ca-root-nss.crt',
170
+ // OS X provided by homebrew (using the default path)
171
+ '/usr/local/etc/openssl/cert.pem',
172
+ // Google app engine
173
+ '/etc/ca-certificates.crt',
174
+ // Windows?
175
+ 'C:\\windows\\system32\\curl-ca-bundle.crt',
176
+ 'C:\\windows\\curl-ca-bundle.crt',
177
+ ];
178
+
179
+ if ($cached) {
180
+ return $cached;
181
+ }
182
+
183
+ if ($ca = ini_get('openssl.cafile')) {
184
+ return $cached = $ca;
185
+ }
186
+
187
+ if ($ca = ini_get('curl.cainfo')) {
188
+ return $cached = $ca;
189
+ }
190
+
191
+ foreach ($cafiles as $filename) {
192
+ if (file_exists($filename)) {
193
+ return $cached = $filename;
194
+ }
195
+ }
196
+
197
+ throw new \RuntimeException(<<< EOT
198
+ No system CA bundle could be found in any of the the common system locations.
199
+ PHP versions earlier than 5.6 are not properly configured to use the system's
200
+ CA bundle by default. In order to verify peer certificates, you will need to
201
+ supply the path on disk to a certificate bundle to the 'verify' request
202
+ option: http://docs.guzzlephp.org/en/latest/clients.html#verify. If you do not
203
+ need a specific certificate bundle, then Mozilla provides a commonly used CA
204
+ bundle which can be downloaded here (provided by the maintainer of cURL):
205
+ https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt. Once
206
+ you have a CA bundle available on disk, you can set the 'openssl.cafile' PHP
207
+ ini setting to point to the path to the file, allowing you to omit the 'verify'
208
+ request option. See http://curl.haxx.se/docs/sslcerts.html for more
209
+ information.
210
+ EOT
211
+ );
212
+ }
213
+
214
+ /**
215
+ * Creates an associative array of lowercase header names to the actual
216
+ * header casing.
217
+ *
218
+ * @param array $headers
219
+ *
220
+ * @return array
221
+ */
222
+ function normalize_header_keys(array $headers)
223
+ {
224
+ $result = [];
225
+ foreach (array_keys($headers) as $key) {
226
+ $result[strtolower($key)] = $key;
227
+ }
228
+
229
+ return $result;
230
+ }
231
+
232
+ /**
233
+ * Returns true if the provided host matches any of the no proxy areas.
234
+ *
235
+ * This method will strip a port from the host if it is present. Each pattern
236
+ * can be matched with an exact match (e.g., "foo.com" == "foo.com") or a
237
+ * partial match: (e.g., "foo.com" == "baz.foo.com" and ".foo.com" ==
238
+ * "baz.foo.com", but ".foo.com" != "foo.com").
239
+ *
240
+ * Areas are matched in the following cases:
241
+ * 1. "*" (without quotes) always matches any hosts.
242
+ * 2. An exact match.
243
+ * 3. The area starts with "." and the area is the last part of the host. e.g.
244
+ * '.mit.edu' will match any host that ends with '.mit.edu'.
245
+ *
246
+ * @param string $host Host to check against the patterns.
247
+ * @param array $noProxyArray An array of host patterns.
248
+ *
249
+ * @return bool
250
+ */
251
+ function is_host_in_noproxy($host, array $noProxyArray)
252
+ {
253
+ if (strlen($host) === 0) {
254
+ throw new \InvalidArgumentException('Empty host provided');
255
+ }
256
+
257
+ // Strip port if present.
258
+ if (strpos($host, ':')) {
259
+ $host = explode($host, ':', 2)[0];
260
+ }
261
+
262
+ foreach ($noProxyArray as $area) {
263
+ // Always match on wildcards.
264
+ if ($area === '*') {
265
+ return true;
266
+ } elseif (empty($area)) {
267
+ // Don't match on empty values.
268
+ continue;
269
+ } elseif ($area === $host) {
270
+ // Exact matches.
271
+ return true;
272
+ } else {
273
+ // Special match if the area when prefixed with ".". Remove any
274
+ // existing leading "." and add a new leading ".".
275
+ $area = '.' . ltrim($area, '.');
276
+ if (substr($host, -(strlen($area))) === $area) {
277
+ return true;
278
+ }
279
+ }
280
+ }
281
+
282
+ return false;
283
+ }
284
+
285
+ /**
286
+ * Wrapper for json_decode that throws when an error occurs.
287
+ *
288
+ * @param string $json JSON data to parse
289
+ * @param bool $assoc When true, returned objects will be converted
290
+ * into associative arrays.
291
+ * @param int $depth User specified recursion depth.
292
+ * @param int $options Bitmask of JSON decode options.
293
+ *
294
+ * @return mixed
295
+ * @throws \InvalidArgumentException if the JSON cannot be decoded.
296
+ * @link http://www.php.net/manual/en/function.json-decode.php
297
+ */
298
+ function json_decode($json, $assoc = false, $depth = 512, $options = 0)
299
+ {
300
+ $data = \json_decode($json, $assoc, $depth, $options);
301
+ if (JSON_ERROR_NONE !== json_last_error()) {
302
+ throw new \InvalidArgumentException(
303
+ 'json_decode error: ' . json_last_error_msg());
304
+ }
305
+
306
+ return $data;
307
+ }
308
+
309
+ /**
310
+ * Wrapper for JSON encoding that throws when an error occurs.
311
+ *
312
+ * @param mixed $value The value being encoded
313
+ * @param int $options JSON encode option bitmask
314
+ * @param int $depth Set the maximum depth. Must be greater than zero.
315
+ *
316
+ * @return string
317
+ * @throws \InvalidArgumentException if the JSON cannot be encoded.
318
+ * @link http://www.php.net/manual/en/function.json-encode.php
319
+ */
320
+ function json_encode($value, $options = 0, $depth = 512)
321
+ {
322
+ $json = \json_encode($value, $options, $depth);
323
+ if (JSON_ERROR_NONE !== json_last_error()) {
324
+ throw new \InvalidArgumentException(
325
+ 'json_encode error: ' . json_last_error_msg());
326
+ }
327
+
328
+ return $json;
329
+ }
lib/Azure/GuzzleHttp/functions_include.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Don't redefine the functions if included multiple times.
4
+ if (!function_exists('GuzzleHttp\uri_template')) {
5
+ require __DIR__ . '/functions.php';
6
+ }
lib/Azure/MicrosoftAzureStorage/Blob/BlobRestProxy.php ADDED
@@ -0,0 +1,2678 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\HttpFormatter;
28
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
29
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
30
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
31
+ use MicrosoftAzure\Storage\Common\Models\ServiceProperties;
32
+ use MicrosoftAzure\Storage\Common\Internal\ServiceRestProxy;
33
+ use MicrosoftAzure\Storage\Blob\Internal\IBlob;
34
+ use MicrosoftAzure\Storage\Blob\Models\BlobServiceOptions;
35
+ use MicrosoftAzure\Storage\Common\Models\GetServicePropertiesResult;
36
+ use MicrosoftAzure\Storage\Blob\Models\ListContainersOptions;
37
+ use MicrosoftAzure\Storage\Blob\Models\ListContainersResult;
38
+ use MicrosoftAzure\Storage\Blob\Models\CreateContainerOptions;
39
+ use MicrosoftAzure\Storage\Blob\Models\GetContainerPropertiesResult;
40
+ use MicrosoftAzure\Storage\Blob\Models\GetContainerACLResult;
41
+ use MicrosoftAzure\Storage\Blob\Models\SetContainerMetadataOptions;
42
+ use MicrosoftAzure\Storage\Blob\Models\DeleteContainerOptions;
43
+ use MicrosoftAzure\Storage\Blob\Models\ListBlobsOptions;
44
+ use MicrosoftAzure\Storage\Blob\Models\ListBlobsResult;
45
+ use MicrosoftAzure\Storage\Blob\Models\BlobType;
46
+ use MicrosoftAzure\Storage\Blob\Models\Block;
47
+ use MicrosoftAzure\Storage\Blob\Models\CreateBlobOptions;
48
+ use MicrosoftAzure\Storage\Blob\Models\BlobProperties;
49
+ use MicrosoftAzure\Storage\Blob\Models\GetBlobPropertiesOptions;
50
+ use MicrosoftAzure\Storage\Blob\Models\GetBlobPropertiesResult;
51
+ use MicrosoftAzure\Storage\Blob\Models\SetBlobPropertiesOptions;
52
+ use MicrosoftAzure\Storage\Blob\Models\SetBlobPropertiesResult;
53
+ use MicrosoftAzure\Storage\Blob\Models\GetBlobMetadataOptions;
54
+ use MicrosoftAzure\Storage\Blob\Models\GetBlobMetadataResult;
55
+ use MicrosoftAzure\Storage\Blob\Models\SetBlobMetadataOptions;
56
+ use MicrosoftAzure\Storage\Blob\Models\SetBlobMetadataResult;
57
+ use MicrosoftAzure\Storage\Blob\Models\GetBlobOptions;
58
+ use MicrosoftAzure\Storage\Blob\Models\GetBlobResult;
59
+ use MicrosoftAzure\Storage\Blob\Models\DeleteBlobOptions;
60
+ use MicrosoftAzure\Storage\Blob\Models\LeaseMode;
61
+ use MicrosoftAzure\Storage\Blob\Models\AcquireLeaseOptions;
62
+ use MicrosoftAzure\Storage\Blob\Models\AcquireLeaseResult;
63
+ use MicrosoftAzure\Storage\Blob\Models\CreateBlobPagesOptions;
64
+ use MicrosoftAzure\Storage\Blob\Models\CreateBlobPagesResult;
65
+ use MicrosoftAzure\Storage\Blob\Models\PageWriteOption;
66
+ use MicrosoftAzure\Storage\Blob\Models\ListPageBlobRangesOptions;
67
+ use MicrosoftAzure\Storage\Blob\Models\ListPageBlobRangesResult;
68
+ use MicrosoftAzure\Storage\Blob\Models\CreateBlobBlockOptions;
69
+ use MicrosoftAzure\Storage\Blob\Models\CommitBlobBlocksOptions;
70
+ use MicrosoftAzure\Storage\Blob\Models\BlockList;
71
+ use MicrosoftAzure\Storage\Blob\Models\ListBlobBlocksOptions;
72
+ use MicrosoftAzure\Storage\Blob\Models\ListBlobBlocksResult;
73
+ use MicrosoftAzure\Storage\Blob\Models\CopyBlobOptions;
74
+ use MicrosoftAzure\Storage\Blob\Models\CreateBlobSnapshotOptions;
75
+ use MicrosoftAzure\Storage\Blob\Models\CreateBlobSnapshotResult;
76
+ use MicrosoftAzure\Storage\Blob\Models\PageRange;
77
+ use MicrosoftAzure\Storage\Blob\Models\CopyBlobResult;
78
+ use MicrosoftAzure\Storage\Blob\Models\BreakLeaseResult;
79
+ use MicrosoftAzure\Storage\Common\Internal\ServiceFunctionThread;
80
+ use GuzzleHttp\Psr7;
81
+
82
+ /**
83
+ * This class constructs HTTP requests and receive HTTP responses for blob
84
+ * service layer.
85
+ *
86
+ * @category Microsoft
87
+ * @package MicrosoftAzure\Storage\Blob
88
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
89
+ * @copyright 2016 Microsoft Corporation
90
+ * @license https://github.com/azure/azure-storage-php/LICENSE
91
+ * @version Release: 0.11.0
92
+ * @link https://github.com/azure/azure-storage-php
93
+ */
94
+ class BlobRestProxy extends ServiceRestProxy implements IBlob
95
+ {
96
+ /**
97
+ * @var int Defaults to 32MB
98
+ */
99
+ private $_SingleBlobUploadThresholdInBytes = Resources::MB_IN_BYTES_32;
100
+
101
+ /**
102
+ * Get the value for SingleBlobUploadThresholdInBytes
103
+ *
104
+ * @return int
105
+ */
106
+ public function getSingleBlobUploadThresholdInBytes()
107
+ {
108
+ return $this->_SingleBlobUploadThresholdInBytes;
109
+ }
110
+
111
+ /**
112
+ * Set the value for SingleBlobUploadThresholdInBytes, Max 64MB
113
+ *
114
+ * @param int $val The max size to send as a single blob block
115
+ *
116
+ * @return none
117
+ */
118
+ public function setSingleBlobUploadThresholdInBytes($val)
119
+ {
120
+ if ($val > Resources::MB_IN_BYTES_64) {
121
+ // What should the proper action here be?
122
+ $val = Resources::MB_IN_BYTES_64;
123
+ } elseif ($val < 1) {
124
+ // another spot that could use looking at
125
+ $val = Resources::MB_IN_BYTES_32;
126
+ }
127
+ $this->_SingleBlobUploadThresholdInBytes = $val;
128
+ }
129
+
130
+ /**
131
+ * Gets the copy blob source name with specified parameters.
132
+ *
133
+ * @param string $containerName The name of the container.
134
+ * @param string $blobName The name of the blob.
135
+ * @param Models\CopyBlobOptions $options The optional parameters.
136
+ *
137
+ * @return string
138
+ */
139
+ private function _getCopyBlobSourceName($containerName, $blobName, $options)
140
+ {
141
+ $sourceName = $this->_getBlobUrl($containerName, $blobName);
142
+
143
+ if (!is_null($options->getSourceSnapshot())) {
144
+ $sourceName .= '?snapshot=' . $options->getSourceSnapshot();
145
+ }
146
+
147
+ return $sourceName;
148
+ }
149
+
150
+ /**
151
+ * Creates URI path for blob.
152
+ *
153
+ * @param string $container The container name.
154
+ * @param string $blob The blob name.
155
+ *
156
+ * @return string
157
+ */
158
+ private function _createPath($container, $blob)
159
+ {
160
+ $encodedBlob = urlencode($blob);
161
+ // Unencode the forward slashes to match what the server expects.
162
+ $encodedBlob = str_replace('%2F', '/', $encodedBlob);
163
+ // Unencode the backward slashes to match what the server expects.
164
+ $encodedBlob = str_replace('%5C', '/', $encodedBlob);
165
+ // Re-encode the spaces (encoded as space) to the % encoding.
166
+ $encodedBlob = str_replace('+', '%20', $encodedBlob);
167
+
168
+ // Empty container means accessing default container
169
+ if (empty($container)) {
170
+ return $encodedBlob;
171
+ } else {
172
+ return $container . '/' . $encodedBlob;
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Creates full URI to the given blob.
178
+ *
179
+ * @param string $container The container name.
180
+ * @param string $blob The blob name.
181
+ *
182
+ * @return string
183
+ */
184
+ private function _getBlobUrl($container, $blob)
185
+ {
186
+ $encodedBlob = urlencode($blob);
187
+ // Unencode the forward slashes to match what the server expects.
188
+ $encodedBlob = str_replace('%2F', '/', $encodedBlob);
189
+ // Unencode the backward slashes to match what the server expects.
190
+ $encodedBlob = str_replace('%5C', '/', $encodedBlob);
191
+ // Re-encode the spaces (encoded as space) to the % encoding.
192
+ $encodedBlob = str_replace('+', '%20', $encodedBlob);
193
+
194
+ // Empty container means accessing default container
195
+ if (empty($container)) {
196
+ $encodedBlob = $encodedBlob;
197
+ } else {
198
+ $encodedBlob = $container . '/' . $encodedBlob;
199
+ }
200
+
201
+ if (substr($encodedBlob, 0, 1) != '/' && substr($this->getUri(), -1, 1) != '/') {
202
+ $encodedBlob = '/' . $encodedBlob;
203
+ }
204
+ return $this->getUri() . $encodedBlob;
205
+ }
206
+
207
+ /**
208
+ * Creates GetBlobPropertiesResult from headers array.
209
+ *
210
+ * @param array $headers The HTTP response headers array.
211
+ *
212
+ * @return GetBlobPropertiesResult
213
+ */
214
+ private function _getBlobPropertiesResultFromResponse($headers)
215
+ {
216
+ $result = new GetBlobPropertiesResult();
217
+ $properties = new BlobProperties();
218
+ $d = $headers[Resources::LAST_MODIFIED];
219
+ $bType = $headers[Resources::X_MS_BLOB_TYPE];
220
+ $cLength = intval($headers[Resources::CONTENT_LENGTH]);
221
+ $lStatus = Utilities::tryGetValue($headers, Resources::X_MS_LEASE_STATUS);
222
+ $cType = Utilities::tryGetValue($headers, Resources::CONTENT_TYPE);
223
+ $cMD5 = Utilities::tryGetValue($headers, Resources::CONTENT_MD5);
224
+ $cEncoding = Utilities::tryGetValue($headers, Resources::CONTENT_ENCODING);
225
+ $cLanguage = Utilities::tryGetValue($headers, Resources::CONTENT_LANGUAGE);
226
+ $cControl = Utilities::tryGetValue($headers, Resources::CACHE_CONTROL);
227
+ $etag = $headers[Resources::ETAG];
228
+ $metadata = $this->getMetadataArray($headers);
229
+
230
+ if (array_key_exists(Resources::X_MS_BLOB_SEQUENCE_NUMBER, $headers)) {
231
+ $sNumber = intval($headers[Resources::X_MS_BLOB_SEQUENCE_NUMBER]);
232
+ $properties->setSequenceNumber($sNumber);
233
+ }
234
+
235
+ $properties->setBlobType($bType);
236
+ $properties->setCacheControl($cControl);
237
+ $properties->setContentEncoding($cEncoding);
238
+ $properties->setContentLanguage($cLanguage);
239
+ $properties->setContentLength($cLength);
240
+ $properties->setContentMD5($cMD5);
241
+ $properties->setContentType($cType);
242
+ $properties->setETag($etag);
243
+ $properties->setLastModified(Utilities::rfc1123ToDateTime($d));
244
+ $properties->setLeaseStatus($lStatus);
245
+
246
+ $result->setProperties($properties);
247
+ $result->setMetadata($metadata);
248
+
249
+ return $result;
250
+ }
251
+
252
+ /**
253
+ * Helper method for getContainerProperties and getContainerMetadata.
254
+ *
255
+ * @param string $container The container name.
256
+ * @param Models\BlobServiceOptions $options The optional parameters.
257
+ * @param string $operation The operation string. Should be
258
+ * 'metadata' to get metadata.
259
+ *
260
+ * @return Models\GetContainerPropertiesResult
261
+ */
262
+ private function _getContainerPropertiesImpl(
263
+ $container,
264
+ $options = null,
265
+ $operation = null
266
+ ) {
267
+ Validate::isString($container, 'container');
268
+
269
+ $method = Resources::HTTP_GET;
270
+ $headers = array();
271
+ $queryParams = array();
272
+ $postParams = array();
273
+ $path = $container;
274
+ $statusCode = Resources::STATUS_OK;
275
+
276
+ if (is_null($options)) {
277
+ $options = new BlobServiceOptions();
278
+ }
279
+
280
+ $this->addOptionalQueryParam(
281
+ $queryParams,
282
+ Resources::QP_REST_TYPE,
283
+ 'container'
284
+ );
285
+ $this->addOptionalQueryParam(
286
+ $queryParams,
287
+ Resources::QP_COMP,
288
+ $operation
289
+ );
290
+ $this->addOptionalQueryParam(
291
+ $queryParams,
292
+ Resources::QP_TIMEOUT,
293
+ $options->getTimeout()
294
+ );
295
+
296
+ $response = $this->send(
297
+ $method,
298
+ $headers,
299
+ $queryParams,
300
+ $postParams,
301
+ $path,
302
+ $statusCode
303
+ );
304
+
305
+ $responseHeaders = HttpFormatter::formatHeaders($response->getHeaders());
306
+
307
+ $result = new GetContainerPropertiesResult();
308
+ $metadata = $this->getMetadataArray($responseHeaders);
309
+ $date = Utilities::tryGetValue($responseHeaders, Resources::LAST_MODIFIED);
310
+ $date = Utilities::rfc1123ToDateTime($date);
311
+ $result->setETag(Utilities::tryGetValue($responseHeaders, Resources::ETAG));
312
+ $result->setMetadata($metadata);
313
+ $result->setLastModified($date);
314
+
315
+ return $result;
316
+ }
317
+
318
+ /**
319
+ * Adds optional create blob headers.
320
+ *
321
+ * @param CreateBlobOptions $options The optional parameters.
322
+ * @param array $headers The HTTP request headers.
323
+ *
324
+ * @return array
325
+ */
326
+ private function _addCreateBlobOptionalHeaders($options, $headers)
327
+ {
328
+ $contentType = $options->getContentType();
329
+ $metadata = $options->getMetadata();
330
+ $blobContentType = $options->getBlobContentType();
331
+ $blobContentEncoding = $options->getBlobContentEncoding();
332
+ $blobContentLanguage = $options->getBlobContentLanguage();
333
+ $blobContentMD5 = $options->getBlobContentMD5();
334
+ $blobCacheControl = $options->getBlobCacheControl();
335
+ $leaseId = $options->getLeaseId();
336
+
337
+ if (!is_null($contentType)) {
338
+ $this->addOptionalHeader(
339
+ $headers,
340
+ Resources::CONTENT_TYPE,
341
+ $options->getContentType()
342
+ );
343
+ } else {
344
+ $this->addOptionalHeader(
345
+ $headers,
346
+ Resources::CONTENT_TYPE,
347
+ Resources::BINARY_FILE_TYPE
348
+ );
349
+ }
350
+ $headers = $this->addMetadataHeaders($headers, $metadata);
351
+ $headers = $this->addOptionalAccessConditionHeader(
352
+ $headers,
353
+ $options->getAccessCondition()
354
+ );
355
+
356
+ $this->addOptionalHeader(
357
+ $headers,
358
+ Resources::CONTENT_ENCODING,
359
+ $options->getContentEncoding()
360
+ );
361
+ $this->addOptionalHeader(
362
+ $headers,
363
+ Resources::CONTENT_LANGUAGE,
364
+ $options->getContentLanguage()
365
+ );
366
+ $this->addOptionalHeader(
367
+ $headers,
368
+ Resources::CONTENT_MD5,
369
+ $options->getContentMD5()
370
+ );
371
+ $this->addOptionalHeader(
372
+ $headers,
373
+ Resources::CACHE_CONTROL,
374
+ $options->getCacheControl()
375
+ );
376
+
377
+ $this->addOptionalHeader(
378
+ $headers,
379
+ Resources::X_MS_LEASE_ID,
380
+ $leaseId
381
+ );
382
+ $this->addOptionalHeader(
383
+ $headers,
384
+ Resources::X_MS_BLOB_CONTENT_TYPE,
385
+ $blobContentType
386
+ );
387
+ $this->addOptionalHeader(
388
+ $headers,
389
+ Resources::X_MS_BLOB_CONTENT_ENCODING,
390
+ $blobContentEncoding
391
+ );
392
+ $this->addOptionalHeader(
393
+ $headers,
394
+ Resources::X_MS_BLOB_CONTENT_LANGUAGE,
395
+ $blobContentLanguage
396
+ );
397
+ $this->addOptionalHeader(
398
+ $headers,
399
+ Resources::X_MS_BLOB_CONTENT_MD5,
400
+ $blobContentMD5
401
+ );
402
+ $this->addOptionalHeader(
403
+ $headers,
404
+ Resources::X_MS_BLOB_CACHE_CONTROL,
405
+ $blobCacheControl
406
+ );
407
+
408
+ return $headers;
409
+ }
410
+
411
+ /**
412
+ * Adds Range header to the headers array.
413
+ *
414
+ * @param array $headers The HTTP request headers.
415
+ * @param integer $start The start byte.
416
+ * @param integer $end The end byte.
417
+ *
418
+ * @return array
419
+ */
420
+ private function _addOptionalRangeHeader($headers, $start, $end)
421
+ {
422
+ if (!is_null($start) || !is_null($end)) {
423
+ $range = $start . '-' . $end;
424
+ $rangeValue = 'bytes=' . $range;
425
+ $this->addOptionalHeader($headers, Resources::RANGE, $rangeValue);
426
+ }
427
+
428
+ return $headers;
429
+ }
430
+
431
+ /**
432
+ * Does the actual work for leasing a blob.
433
+ *
434
+ * @param string $leaseAction The lease action string.
435
+ * @param string $container The container name.
436
+ * @param string $blob The blob to lease name.
437
+ * @param string $leaseId The existing lease id.
438
+ * @param BlobServiceOptions $options The optional parameters.
439
+ * @param AccessCondition $accessCondition The access conditions.
440
+ *
441
+ * @return array
442
+ */
443
+ private function _putLeaseImpl(
444
+ $leaseAction,
445
+ $container,
446
+ $blob,
447
+ $leaseId,
448
+ $options,
449
+ $accessCondition = null
450
+ ) {
451
+ Validate::isString($blob, 'blob');
452
+ Validate::notNullOrEmpty($blob, 'blob');
453
+ Validate::isString($container, 'container');
454
+
455
+ $method = Resources::HTTP_PUT;
456
+ $headers = array();
457
+ $queryParams = array();
458
+ $postParams = array();
459
+ $path = $this->_createPath($container, $blob);
460
+ $statusCode = Resources::EMPTY_STRING;
461
+
462
+ switch ($leaseAction) {
463
+ case LeaseMode::ACQUIRE_ACTION:
464
+ $this->addOptionalHeader($headers, Resources::X_MS_LEASE_DURATION, -1);
465
+ $statusCode = Resources::STATUS_CREATED;
466
+ break;
467
+ case LeaseMode::RENEW_ACTION:
468
+ $statusCode = Resources::STATUS_OK;
469
+ break;
470
+ case LeaseMode::RELEASE_ACTION:
471
+ $statusCode = Resources::STATUS_OK;
472
+ break;
473
+ case LeaseMode::BREAK_ACTION:
474
+ $statusCode = Resources::STATUS_ACCEPTED;
475
+ break;
476
+ default:
477
+ throw new \Exception(Resources::NOT_IMPLEMENTED_MSG);
478
+ }
479
+
480
+ if (!is_null($options)) {
481
+ $options = new BlobServiceOptions();
482
+ }
483
+
484
+ $headers = $this->addOptionalAccessConditionHeader(
485
+ $headers,
486
+ $accessCondition
487
+ );
488
+
489
+ $this->addOptionalHeader($headers, Resources::X_MS_LEASE_ID, $leaseId);
490
+ $this->addOptionalHeader(
491
+ $headers,
492
+ Resources::X_MS_LEASE_ACTION,
493
+ $leaseAction
494
+ );
495
+ $this->addOptionalQueryParam($queryParams, Resources::QP_COMP, 'lease');
496
+ $this->addOptionalQueryParam(
497
+ $queryParams,
498
+ Resources::QP_TIMEOUT,
499
+ $options->getTimeout()
500
+ );
501
+
502
+ $response = $this->send(
503
+ $method,
504
+ $headers,
505
+ $queryParams,
506
+ $postParams,
507
+ $path,
508
+ $statusCode
509
+ );
510
+
511
+ return HttpFormatter::formatHeaders($response->getHeaders());
512
+ }
513
+
514
+ /**
515
+ * Does actual work for create and clear blob pages.
516
+ *
517
+ * @param string $action Either clear or create.
518
+ * @param string $container The container name.
519
+ * @param string $blob The blob name.
520
+ * @param PageRange $range The page ranges.
521
+ * @param string $content The content string.
522
+ * @param CreateBlobPagesOptions $options The optional parameters.
523
+ *
524
+ * @return CreateBlobPagesResult
525
+ */
526
+ private function _updatePageBlobPagesImpl(
527
+ $action,
528
+ $container,
529
+ $blob,
530
+ $range,
531
+ $content,
532
+ $options = null
533
+ ) {
534
+ Validate::isString($blob, 'blob');
535
+ Validate::notNullOrEmpty($blob, 'blob');
536
+ Validate::isString($container, 'container');
537
+ Validate::isString($content, 'content');
538
+ Validate::isTrue(
539
+ $range instanceof PageRange,
540
+ sprintf(
541
+ Resources::INVALID_PARAM_MSG,
542
+ 'range',
543
+ get_class(new PageRange())
544
+ )
545
+ );
546
+ $body = Psr7\stream_for($content);
547
+
548
+ $method = Resources::HTTP_PUT;
549
+ $headers = array();
550
+ $queryParams = array();
551
+ $postParams = array();
552
+ $path = $this->_createPath($container, $blob);
553
+ $statusCode = Resources::STATUS_CREATED;
554
+
555
+ if (is_null($options)) {
556
+ $options = new CreateBlobPagesOptions();
557
+ }
558
+
559
+ $headers = $this->_addOptionalRangeHeader(
560
+ $headers,
561
+ $range->getStart(),
562
+ $range->getEnd()
563
+ );
564
+
565
+ $headers = $this->addOptionalAccessConditionHeader(
566
+ $headers,
567
+ $options->getAccessCondition()
568
+ );
569
+
570
+ $this->addOptionalHeader(
571
+ $headers,
572
+ Resources::X_MS_LEASE_ID,
573
+ $options->getLeaseId()
574
+ );
575
+ $this->addOptionalHeader(
576
+ $headers,
577
+ Resources::CONTENT_MD5,
578
+ $options->getContentMD5()
579
+ );
580
+ $this->addOptionalHeader(
581
+ $headers,
582
+ Resources::X_MS_PAGE_WRITE,
583
+ $action
584
+ );
585
+ $this->addOptionalHeader(
586
+ $headers,
587
+ Resources::CONTENT_TYPE,
588
+ Resources::URL_ENCODED_CONTENT_TYPE
589
+ );
590
+ $this->addOptionalQueryParam($queryParams, Resources::QP_COMP, 'page');
591
+ $this->addOptionalQueryParam(
592
+ $queryParams,
593
+ Resources::QP_TIMEOUT,
594
+ $options->getTimeout()
595
+ );
596
+
597
+ $response = $this->send(
598
+ $method,
599
+ $headers,
600
+ $queryParams,
601
+ $postParams,
602
+ $path,
603
+ $statusCode,
604
+ $body
605
+ );
606
+
607
+ return CreateBlobPagesResult::create(HttpFormatter::formatHeaders($response->getHeaders()));
608
+ }
609
+
610
+ /**
611
+ * Gets the properties of the Blob service.
612
+ *
613
+ * @param Models\BlobServiceOptions $options The optional parameters.
614
+ *
615
+ * @return MicrosoftAzure\Storage\Common\Models\GetServicePropertiesResult
616
+ *
617
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/hh452239.aspx
618
+ */
619
+ public function getServiceProperties($options = null)
620
+ {
621
+ $method = Resources::HTTP_GET;
622
+ $headers = array();
623
+ $queryParams = array();
624
+ $postParams = array();
625
+ $path = Resources::EMPTY_STRING;
626
+ $statusCode = Resources::STATUS_OK;
627
+
628
+ if (is_null($options)) {
629
+ $options = new BlobServiceOptions();
630
+ }
631
+
632
+ $this->addOptionalQueryParam(
633
+ $queryParams,
634
+ Resources::QP_TIMEOUT,
635
+ $options->getTimeout()
636
+ );
637
+ $this->addOptionalQueryParam(
638
+ $queryParams,
639
+ Resources::QP_REST_TYPE,
640
+ 'service'
641
+ );
642
+ $this->addOptionalQueryParam(
643
+ $queryParams,
644
+ Resources::QP_COMP,
645
+ 'properties'
646
+ );
647
+
648
+ $response = $this->send(
649
+ $method,
650
+ $headers,
651
+ $queryParams,
652
+ $postParams,
653
+ $path,
654
+ $statusCode
655
+ );
656
+ $parsed = $this->dataSerializer->unserialize($response->getBody());
657
+
658
+ return GetServicePropertiesResult::create($parsed);
659
+ }
660
+
661
+ /**
662
+ * Sets the properties of the Blob service.
663
+ *
664
+ * It's recommended to use getServiceProperties, alter the returned object and
665
+ * then use setServiceProperties with this altered object.
666
+ *
667
+ * @param ServiceProperties $serviceProperties The service properties.
668
+ * @param Models\BlobServiceOptions $options The optional parameters.
669
+ *
670
+ * @return none
671
+ *
672
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/hh452235.aspx
673
+ */
674
+ public function setServiceProperties($serviceProperties, $options = null)
675
+ {
676
+ Validate::isTrue(
677
+ $serviceProperties instanceof ServiceProperties,
678
+ Resources::INVALID_SVC_PROP_MSG
679
+ );
680
+
681
+ $method = Resources::HTTP_PUT;
682
+ $headers = array();
683
+ $queryParams = array();
684
+ $postParams = array();
685
+ $statusCode = Resources::STATUS_ACCEPTED;
686
+ $path = Resources::EMPTY_STRING;
687
+ $body = $serviceProperties->toXml($this->dataSerializer);
688
+
689
+ if (is_null($options)) {
690
+ $options = new BlobServiceOptions();
691
+ }
692
+
693
+ $this->addOptionalQueryParam(
694
+ $queryParams,
695
+ Resources::QP_REST_TYPE,
696
+ 'service'
697
+ );
698
+ $this->addOptionalQueryParam(
699
+ $queryParams,
700
+ Resources::QP_COMP,
701
+ 'properties'
702
+ );
703
+ $this->addOptionalQueryParam(
704
+ $queryParams,
705
+ Resources::QP_TIMEOUT,
706
+ $options->getTimeout()
707
+ );
708
+ $this->addOptionalHeader(
709
+ $headers,
710
+ Resources::CONTENT_TYPE,
711
+ Resources::URL_ENCODED_CONTENT_TYPE
712
+ );
713
+
714
+ $this->send(
715
+ $method,
716
+ $headers,
717
+ $queryParams,
718
+ $postParams,
719
+ $path,
720
+ $statusCode,
721
+ $body
722
+ );
723
+ }
724
+
725
+ /**
726
+ * Lists all of the containers in the given storage account.
727
+ *
728
+ * @param Models\ListContainersOptions $options The optional parameters.
729
+ *
730
+ * @return MicrosoftAzure\Storage\Blob\Models\ListContainersResult
731
+ *
732
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179352.aspx
733
+ */
734
+ public function listContainers($options = null)
735
+ {
736
+ $method = Resources::HTTP_GET;
737
+ $headers = array();
738
+ $queryParams = array();
739
+ $postParams = array();
740
+ $path = Resources::EMPTY_STRING;
741
+ $statusCode = Resources::STATUS_OK;
742
+
743
+ if (is_null($options)) {
744
+ $options = new ListContainersOptions();
745
+ }
746
+
747
+ $this->addOptionalQueryParam(
748
+ $queryParams,
749
+ Resources::QP_TIMEOUT,
750
+ $options->getTimeout()
751
+ );
752
+ $this->addOptionalQueryParam(
753
+ $queryParams,
754
+ Resources::QP_COMP,
755
+ 'list'
756
+ );
757
+ $this->addOptionalQueryParam(
758
+ $queryParams,
759
+ Resources::QP_PREFIX,
760
+ $options->getPrefix()
761
+ );
762
+ $this->addOptionalQueryParam(
763
+ $queryParams,
764
+ Resources::QP_MARKER,
765
+ $options->getMarker()
766
+ );
767
+ $this->addOptionalQueryParam(
768
+ $queryParams,
769
+ Resources::QP_MAX_RESULTS,
770
+ $options->getMaxResults()
771
+ );
772
+ $isInclude = $options->getIncludeMetadata();
773
+ $isInclude = $isInclude ? 'metadata' : null;
774
+ $this->addOptionalQueryParam(
775
+ $queryParams,
776
+ Resources::QP_INCLUDE,
777
+ $isInclude
778
+ );
779
+
780
+ $response = $this->send(
781
+ $method,
782
+ $headers,
783
+ $queryParams,
784
+ $postParams,
785
+ $path,
786
+ $statusCode
787
+ );
788
+
789
+ $parsed = $this->dataSerializer->unserialize($response->getBody());
790
+
791
+ return ListContainersResult::create($parsed);
792
+ }
793
+
794
+ /**
795
+ * Creates a new container in the given storage account.
796
+ *
797
+ * @param string $container The container name.
798
+ * @param Models\CreateContainerOptions $options The optional parameters.
799
+ *
800
+ * @return none
801
+ *
802
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179468.aspx
803
+ */
804
+ public function createContainer($container, $options = null)
805
+ {
806
+ Validate::isString($container, 'container');
807
+ Validate::notNullOrEmpty($container, 'container');
808
+
809
+ $method = Resources::HTTP_PUT;
810
+ $headers = array();
811
+ $postParams = array();
812
+ $queryParams = array(Resources::QP_REST_TYPE => 'container');
813
+ $path = $container;
814
+ $statusCode = Resources::STATUS_CREATED;
815
+
816
+ if (is_null($options)) {
817
+ $options = new CreateContainerOptions();
818
+ }
819
+
820
+ $this->addOptionalQueryParam(
821
+ $queryParams,
822
+ Resources::QP_TIMEOUT,
823
+ $options->getTimeout()
824
+ );
825
+
826
+ $metadata = $options->getMetadata();
827
+ $headers = $this->generateMetadataHeaders($metadata);
828
+ $this->addOptionalHeader(
829
+ $headers,
830
+ Resources::X_MS_BLOB_PUBLIC_ACCESS,
831
+ $options->getPublicAccess()
832
+ );
833
+
834
+ $this->send(
835
+ $method,
836
+ $headers,
837
+ $queryParams,
838
+ $postParams,
839
+ $path,
840
+ $statusCode
841
+ );
842
+ }
843
+
844
+ /**
845
+ * Creates a new container in the given storage account.
846
+ *
847
+ * @param string $container The container name.
848
+ * @param Models\DeleteContainerOptions $options The optional parameters.
849
+ *
850
+ * @return none
851
+ *
852
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179408.aspx
853
+ */
854
+ public function deleteContainer($container, $options = null)
855
+ {
856
+ Validate::isString($container, 'container');
857
+ Validate::notNullOrEmpty($container, 'container');
858
+
859
+ $method = Resources::HTTP_DELETE;
860
+ $headers = array();
861
+ $postParams = array();
862
+ $queryParams = array();
863
+ $path = $container;
864
+ $statusCode = Resources::STATUS_ACCEPTED;
865
+
866
+ if (is_null($options)) {
867
+ $options = new DeleteContainerOptions();
868
+ }
869
+
870
+ $headers = $this->addOptionalAccessConditionHeader(
871
+ $headers,
872
+ $options->getAccessCondition()
873
+ );
874
+
875
+ $this->addOptionalQueryParam(
876
+ $queryParams,
877
+ Resources::QP_TIMEOUT,
878
+ $options->getTimeout()
879
+ );
880
+ $this->addOptionalQueryParam(
881
+ $queryParams,
882
+ Resources::QP_REST_TYPE,
883
+ 'container'
884
+ );
885
+
886
+ $this->send(
887
+ $method,
888
+ $headers,
889
+ $queryParams,
890
+ $postParams,
891
+ $path,
892
+ $statusCode
893
+ );
894
+ }
895
+
896
+ /**
897
+ * Returns all properties and metadata on the container.
898
+ *
899
+ * @param string $container name
900
+ * @param Models\BlobServiceOptions $options optional parameters
901
+ *
902
+ * @return Models\GetContainerPropertiesResult
903
+ *
904
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179370.aspx
905
+ */
906
+ public function getContainerProperties($container, $options = null)
907
+ {
908
+ return $this->_getContainerPropertiesImpl($container, $options);
909
+ }
910
+
911
+ /**
912
+ * Returns only user-defined metadata for the specified container.
913
+ *
914
+ * @param string $container name
915
+ * @param Models\BlobServiceOptions $options optional parameters
916
+ *
917
+ * @return Models\GetContainerPropertiesResult
918
+ *
919
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691976.aspx
920
+ */
921
+ public function getContainerMetadata($container, $options = null)
922
+ {
923
+ return $this->_getContainerPropertiesImpl($container, $options, 'metadata');
924
+ }
925
+
926
+ /**
927
+ * Gets the access control list (ACL) and any container-level access policies
928
+ * for the container.
929
+ *
930
+ * @param string $container The container name.
931
+ * @param Models\BlobServiceOptions $options The optional parameters.
932
+ *
933
+ * @return Models\GetContainerAclResult
934
+ *
935
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179469.aspx
936
+ */
937
+ public function getContainerAcl($container, $options = null)
938
+ {
939
+ Validate::isString($container, 'container');
940
+
941
+ $method = Resources::HTTP_GET;
942
+ $headers = array();
943
+ $postParams = array();
944
+ $queryParams = array();
945
+ $path = $container;
946
+ $statusCode = Resources::STATUS_OK;
947
+
948
+ if (is_null($options)) {
949
+ $options = new BlobServiceOptions();
950
+ }
951
+
952
+ $this->addOptionalQueryParam(
953
+ $queryParams,
954
+ Resources::QP_TIMEOUT,
955
+ $options->getTimeout()
956
+ );
957
+ $this->addOptionalQueryParam(
958
+ $queryParams,
959
+ Resources::QP_REST_TYPE,
960
+ 'container'
961
+ );
962
+ $this->addOptionalQueryParam(
963
+ $queryParams,
964
+ Resources::QP_COMP,
965
+ 'acl'
966
+ );
967
+
968
+ $response = $this->send(
969
+ $method,
970
+ $headers,
971
+ $queryParams,
972
+ $postParams,
973
+ $path,
974
+ $statusCode
975
+ );
976
+
977
+ $responseHeaders = HttpFormatter::formatHeaders($response->getHeaders());
978
+
979
+ $access = Utilities::tryGetValue($responseHeaders, Resources::X_MS_BLOB_PUBLIC_ACCESS);
980
+ $etag = Utilities::tryGetValue($responseHeaders, Resources::ETAG);
981
+ $modified = Utilities::tryGetValue($responseHeaders, Resources::LAST_MODIFIED);
982
+ $modifiedDate = Utilities::convertToDateTime($modified);
983
+ $parsed = $this->dataSerializer->unserialize($response->getBody());
984
+
985
+ return GetContainerAclResult::create($access, $etag, $modifiedDate, $parsed);
986
+ }
987
+
988
+ /**
989
+ * Sets the ACL and any container-level access policies for the container.
990
+ *
991
+ * @param string $container name
992
+ * @param Models\ContainerAcl $acl access control list for container
993
+ * @param Models\BlobServiceOptions $options optional parameters
994
+ *
995
+ * @return none
996
+ *
997
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179391.aspx
998
+ */
999
+ public function setContainerAcl($container, $acl, $options = null)
1000
+ {
1001
+ Validate::isString($container, 'container');
1002
+ Validate::notNullOrEmpty($acl, 'acl');
1003
+
1004
+ $method = Resources::HTTP_PUT;
1005
+ $headers = array();
1006
+ $postParams = array();
1007
+ $queryParams = array();
1008
+ $path = $container;
1009
+ $statusCode = Resources::STATUS_OK;
1010
+ $body = $acl->toXml($this->dataSerializer);
1011
+
1012
+ if (is_null($options)) {
1013
+ $options = new BlobServiceOptions();
1014
+ }
1015
+
1016
+ $this->addOptionalQueryParam(
1017
+ $queryParams,
1018
+ Resources::QP_TIMEOUT,
1019
+ $options->getTimeout()
1020
+ );
1021
+ $this->addOptionalQueryParam(
1022
+ $queryParams,
1023
+ Resources::QP_REST_TYPE,
1024
+ 'container'
1025
+ );
1026
+ $this->addOptionalQueryParam(
1027
+ $queryParams,
1028
+ Resources::QP_COMP,
1029
+ 'acl'
1030
+ );
1031
+ $this->addOptionalHeader(
1032
+ $headers,
1033
+ Resources::X_MS_BLOB_PUBLIC_ACCESS,
1034
+ $acl->getPublicAccess()
1035
+ );
1036
+ $this->addOptionalHeader(
1037
+ $headers,
1038
+ Resources::CONTENT_TYPE,
1039
+ Resources::URL_ENCODED_CONTENT_TYPE
1040
+ );
1041
+
1042
+ $this->send(
1043
+ $method,
1044
+ $headers,
1045
+ $queryParams,
1046
+ $postParams,
1047
+ $path,
1048
+ $statusCode,
1049
+ $body
1050
+ );
1051
+ }
1052
+
1053
+ /**
1054
+ * Sets metadata headers on the container.
1055
+ *
1056
+ * @param string $container name
1057
+ * @param array $metadata metadata key/value pair.
1058
+ * @param Models\SetContainerMetadataOptions $options optional parameters
1059
+ *
1060
+ * @return none
1061
+ *
1062
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179362.aspx
1063
+ */
1064
+ public function setContainerMetadata($container, $metadata, $options = null)
1065
+ {
1066
+ Validate::isString($container, 'container');
1067
+ $this->validateMetadata($metadata);
1068
+
1069
+ $method = Resources::HTTP_PUT;
1070
+ $headers = $this->generateMetadataHeaders($metadata);
1071
+ $postParams = array();
1072
+ $queryParams = array();
1073
+ $path = $container;
1074
+ $statusCode = Resources::STATUS_OK;
1075
+
1076
+ if (is_null($options)) {
1077
+ $options = new SetContainerMetadataOptions();
1078
+ }
1079
+
1080
+ $this->addOptionalQueryParam(
1081
+ $queryParams,
1082
+ Resources::QP_TIMEOUT,
1083
+ $options->getTimeout()
1084
+ );
1085
+ $this->addOptionalQueryParam(
1086
+ $queryParams,
1087
+ Resources::QP_REST_TYPE,
1088
+ 'container'
1089
+ );
1090
+ $this->addOptionalQueryParam(
1091
+ $queryParams,
1092
+ Resources::QP_COMP,
1093
+ 'metadata'
1094
+ );
1095
+
1096
+ $headers = $this->addOptionalAccessConditionHeader(
1097
+ $headers,
1098
+ $options->getAccessCondition()
1099
+ );
1100
+
1101
+ $this->send(
1102
+ $method,
1103
+ $headers,
1104
+ $queryParams,
1105
+ $postParams,
1106
+ $path,
1107
+ $statusCode
1108
+ );
1109
+ }
1110
+
1111
+ /**
1112
+ * Lists all of the blobs in the given container.
1113
+ *
1114
+ * @param string $container The container name.
1115
+ * @param Models\ListBlobsOptions $options The optional parameters.
1116
+ *
1117
+ * @return Models\ListBlobsResult
1118
+ *
1119
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd135734.aspx
1120
+ */
1121
+ public function listBlobs($container, $options = null)
1122
+ {
1123
+ Validate::isString($container, 'container');
1124
+
1125
+ $method = Resources::HTTP_GET;
1126
+ $headers = array();
1127
+ $postParams = array();
1128
+ $queryParams = array();
1129
+ $path = $container;
1130
+ $statusCode = Resources::STATUS_OK;
1131
+
1132
+ if (is_null($options)) {
1133
+ $options = new ListBlobsOptions();
1134
+ }
1135
+
1136
+ $this->addOptionalQueryParam(
1137
+ $queryParams,
1138
+ Resources::QP_TIMEOUT,
1139
+ $options->getTimeout()
1140
+ );
1141
+ $this->addOptionalQueryParam(
1142
+ $queryParams,
1143
+ Resources::QP_REST_TYPE,
1144
+ 'container'
1145
+ );
1146
+ $this->addOptionalQueryParam(
1147
+ $queryParams,
1148
+ Resources::QP_COMP,
1149
+ 'list'
1150
+ );
1151
+ $this->addOptionalQueryParam(
1152
+ $queryParams,
1153
+ Resources::QP_PREFIX,
1154
+ str_replace('\\', '/', $options->getPrefix())
1155
+ );
1156
+ $this->addOptionalQueryParam(
1157
+ $queryParams,
1158
+ Resources::QP_MARKER,
1159
+ $options->getMarker()
1160
+ );
1161
+ $this->addOptionalQueryParam(
1162
+ $queryParams,
1163
+ Resources::QP_DELIMITER,
1164
+ $options->getDelimiter()
1165
+ );
1166
+ $this->addOptionalQueryParam(
1167
+ $queryParams,
1168
+ Resources::QP_MAX_RESULTS,
1169
+ $options->getMaxResults()
1170
+ );
1171
+
1172
+ $includeMetadata = $options->getIncludeMetadata();
1173
+ $includeSnapshots = $options->getIncludeSnapshots();
1174
+ $includeUncommittedBlobs = $options->getIncludeUncommittedBlobs();
1175
+
1176
+ $includeValue = static::groupQueryValues(
1177
+ array(
1178
+ $includeMetadata ? 'metadata' : null,
1179
+ $includeSnapshots ? 'snapshots' : null,
1180
+ $includeUncommittedBlobs ? 'uncommittedblobs' : null
1181
+ )
1182
+ );
1183
+
1184
+ $this->addOptionalQueryParam(
1185
+ $queryParams,
1186
+ Resources::QP_INCLUDE,
1187
+ $includeValue
1188
+ );
1189
+
1190
+ $response = $this->send(
1191
+ $method,
1192
+ $headers,
1193
+ $queryParams,
1194
+ $postParams,
1195
+ $path,
1196
+ $statusCode
1197
+ );
1198
+
1199
+ $parsed = $this->dataSerializer->unserialize($response->getBody());
1200
+
1201
+ return ListBlobsResult::create($parsed);
1202
+ }
1203
+
1204
+ /**
1205
+ * Creates a new page blob. Note that calling createPageBlob to create a page
1206
+ * blob only initializes the blob.
1207
+ * To add content to a page blob, call createBlobPages method.
1208
+ *
1209
+ * @param string $container The container name.
1210
+ * @param string $blob The blob name.
1211
+ * @param integer $length Specifies the maximum size for the
1212
+ * page blob, up to 1 TB. The page blob size must be aligned to a 512-byte
1213
+ * boundary.
1214
+ * @param Models\CreateBlobOptions $options The optional parameters.
1215
+ *
1216
+ * @return CopyBlobResult
1217
+ *
1218
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179451.aspx
1219
+ */
1220
+ public function createPageBlob($container, $blob, $length, $options = null)
1221
+ {
1222
+ Validate::isString($container, 'container');
1223
+ Validate::isString($blob, 'blob');
1224
+ Validate::notNullOrEmpty($blob, 'blob');
1225
+ Validate::isInteger($length, 'length');
1226
+ Validate::notNull($length, 'length');
1227
+
1228
+ $method = Resources::HTTP_PUT;
1229
+ $headers = array();
1230
+ $postParams = array();
1231
+ $queryParams = array();
1232
+ $path = $this->_createPath($container, $blob);
1233
+ $statusCode = Resources::STATUS_CREATED;
1234
+
1235
+ if (is_null($options)) {
1236
+ $options = new CreateBlobOptions();
1237
+ }
1238
+
1239
+ $this->addOptionalHeader(
1240
+ $headers,
1241
+ Resources::X_MS_BLOB_TYPE,
1242
+ BlobType::PAGE_BLOB
1243
+ );
1244
+ $this->addOptionalHeader(
1245
+ $headers,
1246
+ Resources::X_MS_BLOB_CONTENT_LENGTH,
1247
+ $length
1248
+ );
1249
+ $this->addOptionalHeader(
1250
+ $headers,
1251
+ Resources::X_MS_BLOB_SEQUENCE_NUMBER,
1252
+ $options->getSequenceNumber()
1253
+ );
1254
+ $headers = $this->_addCreateBlobOptionalHeaders($options, $headers);
1255
+
1256
+ $this->addOptionalQueryParam(
1257
+ $queryParams,
1258
+ Resources::QP_TIMEOUT,
1259
+ $options->getTimeout()
1260
+ );
1261
+
1262
+ $response = $this->send(
1263
+ $method,
1264
+ $headers,
1265
+ $queryParams,
1266
+ $postParams,
1267
+ $path,
1268
+ $statusCode
1269
+ );
1270
+
1271
+ return CopyBlobResult::create(HttpFormatter::formatHeaders($response->getHeaders()));
1272
+ }
1273
+
1274
+ /**
1275
+ * Creates a new block blob or updates the content of an existing block blob.
1276
+ *
1277
+ * Updating an existing block blob overwrites any existing metadata on the blob.
1278
+ * Partial updates are not supported with createBlockBlob the content of the
1279
+ * existing blob is overwritten with the content of the new blob. To perform a
1280
+ * partial update of the content of a block blob, use the createBlockList
1281
+ * method.
1282
+ * Note that the default content type is application/octet-stream.
1283
+ *
1284
+ * @param string $container The name of the container.
1285
+ * @param string $blob The name of the blob.
1286
+ * @param string|resource|StreamInterface $content The content of the blob.
1287
+ * @param CreateBlobOptions $options The optional parameters.
1288
+ *
1289
+ * @return CopyBlobResult
1290
+ *
1291
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179451.aspx
1292
+ */
1293
+ public function createBlockBlob($container, $blob, $content, $options = null)
1294
+ {
1295
+ Validate::isString($container, 'container');
1296
+ Validate::isString($blob, 'blob');
1297
+ Validate::notNullOrEmpty($blob, 'blob');
1298
+ $body = Psr7\stream_for($content);
1299
+ Validate::isTrue(
1300
+ $options == null ||
1301
+ $options instanceof CreateBlobOptions,
1302
+ sprintf(
1303
+ Resources::INVALID_PARAM_MSG,
1304
+ 'options',
1305
+ get_class(new CreateBlobOptions())
1306
+ )
1307
+ );
1308
+
1309
+ $method = Resources::HTTP_PUT;
1310
+ $headers = array();
1311
+ $postParams = array();
1312
+ $queryParams = array();
1313
+ $path = $this->_createPath($container, $blob);
1314
+ $statusCode = Resources::STATUS_CREATED;
1315
+
1316
+ if (is_null($options)) {
1317
+ $options = new CreateBlobOptions();
1318
+ }
1319
+
1320
+ //If the size of the stream is not seekable or larger than the single
1321
+ //upload threashold then call concurrent upload. Otherwise call putBlob.
1322
+ if (!Utilities::isStreamLargerThanSizeOrNotSeekable(
1323
+ $body,
1324
+ $this->_SingleBlobUploadThresholdInBytes
1325
+ )) {
1326
+ $headers = $this->_addCreateBlobOptionalHeaders($options, $headers);
1327
+
1328
+ $this->addOptionalHeader(
1329
+ $headers,
1330
+ Resources::X_MS_BLOB_TYPE,
1331
+ BlobType::BLOCK_BLOB
1332
+ );
1333
+ $this->addOptionalQueryParam(
1334
+ $queryParams,
1335
+ Resources::QP_TIMEOUT,
1336
+ $options->getTimeout()
1337
+ );
1338
+
1339
+ $response = $this->send(
1340
+ $method,
1341
+ $headers,
1342
+ $queryParams,
1343
+ $postParams,
1344
+ $path,
1345
+ $statusCode,
1346
+ $body
1347
+ );
1348
+ return CopyBlobResult::create(
1349
+ HttpFormatter::formatHeaders($response->getHeaders())
1350
+ );
1351
+ } else {
1352
+ // This is for large or failsafe upload
1353
+ return $this->createBlockBlobConcurrent(
1354
+ $container,
1355
+ $blob,
1356
+ $body,
1357
+ $options
1358
+ );
1359
+ }
1360
+ }
1361
+
1362
+ /**
1363
+ * Clears a range of pages from the blob.
1364
+ *
1365
+ * @param string $container name of the container
1366
+ * @param string $blob name of the blob
1367
+ * @param Models\PageRange $range Can be up to the value of
1368
+ * the blob's full size.
1369
+ * Note that ranges must be
1370
+ * aligned to 512 (0-511,
1371
+ * 512-1023)
1372
+ * @param Models\CreateBlobPagesOptions $options optional parameters
1373
+ *
1374
+ * @return Models\CreateBlobPagesResult.
1375
+ *
1376
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691975.aspx
1377
+ */
1378
+ public function clearBlobPages($container, $blob, $range, $options = null)
1379
+ {
1380
+ return $this->_updatePageBlobPagesImpl(
1381
+ PageWriteOption::CLEAR_OPTION,
1382
+ $container,
1383
+ $blob,
1384
+ $range,
1385
+ Resources::EMPTY_STRING,
1386
+ $options
1387
+ );
1388
+ }
1389
+
1390
+ /**
1391
+ * Creates a range of pages to a page blob.
1392
+ *
1393
+ * @param string $container name of the container
1394
+ * @param string $blob name of the blob
1395
+ * @param Models\PageRange $range Can be up to 4 MB in
1396
+ * size. Note that ranges
1397
+ * must be aligned to 512
1398
+ * (0-511, 512-1023)
1399
+ * @param string|resource|StreamInterface $content the blob contents.
1400
+ * @param Models\CreateBlobPagesOptions $options optional parameters
1401
+ *
1402
+ * @return Models\CreateBlobPagesResult.
1403
+ *
1404
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691975.aspx
1405
+ */
1406
+ public function createBlobPages(
1407
+ $container,
1408
+ $blob,
1409
+ $range,
1410
+ $content,
1411
+ $options = null
1412
+ ) {
1413
+ $contentStream = Psr7\stream_for($content);
1414
+ //because the content is at most 4MB long, can retrieve all the data
1415
+ //here at once.
1416
+ $body = $contentStream->getContents();
1417
+
1418
+ //if the range is not align to 512, throw exception.
1419
+ $chunks = (int)($range->getLength() / 512);
1420
+ if ($chunks * 512 != $range->getLength()) {
1421
+ throw new \RuntimeException(Resources::ERROR_RANGE_NOT_ALIGN_TO_512);
1422
+ }
1423
+
1424
+ return $this->_updatePageBlobPagesImpl(
1425
+ PageWriteOption::UPDATE_OPTION,
1426
+ $container,
1427
+ $blob,
1428
+ $range,
1429
+ $body,
1430
+ $options
1431
+ );
1432
+ }
1433
+
1434
+ /**
1435
+ * Creates a new block to be committed as part of a block blob.
1436
+ *
1437
+ * @param string $container name of the container
1438
+ * @param string $blob name of the blob
1439
+ * @param string $blockId must be less than or
1440
+ * equal to 64 bytes in
1441
+ * size. For a given blob,
1442
+ * the length of the value
1443
+ * specified for the
1444
+ * blockid parameter must
1445
+ * be the same size for
1446
+ * each block.
1447
+ * @param resource|string|StreamInterface $content the blob block contents
1448
+ * @param Models\CreateBlobBlockOptions $options optional parameters
1449
+ *
1450
+ * @return \MicrosoftAzure\Storage\Blob\Models\CopyBlobResult
1451
+ *
1452
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx
1453
+ */
1454
+ public function createBlobBlock(
1455
+ $container,
1456
+ $blob,
1457
+ $blockId,
1458
+ $content,
1459
+ $options = null
1460
+ ) {
1461
+ Validate::isString($container, 'container');
1462
+ Validate::isString($blob, 'blob');
1463
+ Validate::notNullOrEmpty($blob, 'blob');
1464
+ Validate::isString($blockId, 'blockId');
1465
+ Validate::notNullOrEmpty($blockId, 'blockId');
1466
+
1467
+ if (is_null($options)) {
1468
+ $options = new CreateBlobBlockOptions();
1469
+ }
1470
+
1471
+ $method = Resources::HTTP_PUT;
1472
+ $headers = $this->createBlobBlockHeader($options);
1473
+ $postParams = array();
1474
+ $queryParams = $this->createBlobBlockQueryParams($options, $blockId);
1475
+ $path = $this->_createPath($container, $blob);
1476
+ $statusCode = Resources::STATUS_CREATED;
1477
+ $contentStream = Psr7\stream_for($content);
1478
+ $body = $contentStream->getContents();
1479
+
1480
+ $response = $this->send(
1481
+ $method,
1482
+ $headers,
1483
+ $queryParams,
1484
+ $postParams,
1485
+ $path,
1486
+ $statusCode,
1487
+ $body
1488
+ );
1489
+
1490
+ return CopyBlobResult::create(
1491
+ HttpFormatter::formatHeaders($response->getHeaders())
1492
+ );
1493
+ }
1494
+
1495
+ /**
1496
+ * create the header for createBlobBlock(s)
1497
+ * @param array $options the option of the request
1498
+ *
1499
+ * @return array
1500
+ */
1501
+ protected function createBlobBlockHeader($options)
1502
+ {
1503
+ $headers = array();
1504
+ $this->addOptionalHeader(
1505
+ $headers,
1506
+ Resources::X_MS_LEASE_ID,
1507
+ $options->getLeaseId()
1508
+ );
1509
+ $this->addOptionalHeader(
1510
+ $headers,
1511
+ Resources::CONTENT_MD5,
1512
+ $options->getContentMD5()
1513
+ );
1514
+ $this->addOptionalHeader(
1515
+ $headers,
1516
+ Resources::CONTENT_TYPE,
1517
+ Resources::URL_ENCODED_CONTENT_TYPE
1518
+ );
1519
+
1520
+ return $headers;
1521
+ }
1522
+
1523
+ /**
1524
+ * create the query params for createBlobBlock(s)
1525
+ * @param array $options the option of the request
1526
+ * @param string $blockId the block id of the block.
1527
+ *
1528
+ * @return array the constructed query parameters.
1529
+ */
1530
+ protected function createBlobBlockQueryParams($options, $blockId)
1531
+ {
1532
+ $queryParams = array();
1533
+ $this->addOptionalQueryParam(
1534
+ $queryParams,
1535
+ Resources::QP_TIMEOUT,
1536
+ $options->getTimeout()
1537
+ );
1538
+ $this->addOptionalQueryParam(
1539
+ $queryParams,
1540
+ Resources::QP_COMP,
1541
+ 'block'
1542
+ );
1543
+ $this->addOptionalQueryParam(
1544
+ $queryParams,
1545
+ Resources::QP_BLOCKID,
1546
+ $blockId
1547
+ );
1548
+
1549
+ return $queryParams;
1550
+ }
1551
+
1552
+ /**
1553
+ * This method creates the blob blocks. This method will send the request
1554
+ * concurrently for better performance.
1555
+ *
1556
+ * @param string $container The name of the container
1557
+ * @param string $blob The name of the blob
1558
+ * @param StreamInterface $content The stream that contains the content
1559
+ * @param CreateBlobOptions $options The array that contains all the option
1560
+ *
1561
+ * @return \MicrosoftAzure\Storage\Blob\Models\CopyBlobResult
1562
+ */
1563
+ protected function createBlockBlobConcurrent(
1564
+ $container,
1565
+ $blob,
1566
+ $content,
1567
+ $options = null
1568
+ ) {
1569
+ Validate::isString($container, 'container');
1570
+ Validate::isString($blob, 'blob');
1571
+ $contentStream = Psr7\stream_for($content);
1572
+
1573
+ $createBlobBlockOptions = new CreateBlobBlockOptions();
1574
+ if (is_null($options)) {
1575
+ $options = new CreateBlobOptions();
1576
+ }
1577
+
1578
+ $method = Resources::HTTP_PUT;
1579
+ $headers = $this->createBlobBlockHeader($createBlobBlockOptions);
1580
+ $postParams = array();
1581
+ $path = $this->_createPath($container, $blob);
1582
+
1583
+ $blockIds = array();
1584
+ // if threshold is lower than 4mb, honor threshold, else use 4mb
1585
+ $blockSize = (
1586
+ $this->_SingleBlobUploadThresholdInBytes
1587
+ < Resources::MB_IN_BYTES_4) ?
1588
+ $this->_SingleBlobUploadThresholdInBytes : Resources::MB_IN_BYTES_4;
1589
+ $counter = 0;
1590
+ //create the generator for requests.
1591
+ //this generator also constructs the blockId array on the fly.
1592
+ $generator = function () use (
1593
+ $contentStream,
1594
+ &$blockIds,
1595
+ $blockSize,
1596
+ $createBlobBlockOptions,
1597
+ $method,
1598
+ $headers,
1599
+ $postParams,
1600
+ $path,
1601
+ &$counter
1602
+ ) {
1603
+ //read the content.
1604
+ $blockContent = $contentStream->read($blockSize);
1605
+ //construct the blockId
1606
+ $blockId = base64_encode(
1607
+ str_pad($counter++, 6, '0', STR_PAD_LEFT)
1608
+ );
1609
+ $size = strlen($blockContent);
1610
+ if ($size == 0) {
1611
+ return null;
1612
+ }
1613
+ //add the id to array.
1614
+ array_push($blockIds, new Block($blockId, 'Uncommitted'));
1615
+ $queryParams = $this->createBlobBlockQueryParams(
1616
+ $createBlobBlockOptions,
1617
+ $blockId
1618
+ );
1619
+ //return the array of requests.
1620
+ return $this->createRequest(
1621
+ $method,
1622
+ $headers,
1623
+ $queryParams,
1624
+ $postParams,
1625
+ $path,
1626
+ $blockContent
1627
+ );
1628
+ };
1629
+
1630
+ //add number of concurrency if specified int options.
1631
+ $clientOptions = $options->getNumberOfConcurrency() == null?
1632
+ array() : array($options->getNumberOfConcurrency);
1633
+
1634
+ //Send the request concurrently.
1635
+ //Does not need to evaluate the results. If operation not successful,
1636
+ //exception will be thrown.
1637
+ $this->sendConcurrent(
1638
+ array(),
1639
+ $generator,
1640
+ Resources::STATUS_CREATED,
1641
+ $clientOptions
1642
+ );
1643
+
1644
+ $response = $this->commitBlobBlocks(
1645
+ $container,
1646
+ $blob,
1647
+ $blockIds,
1648
+ $options
1649
+ );
1650
+
1651
+ return CopyBlobResult::create(
1652
+ HttpFormatter::formatHeaders(
1653
+ $response->getHeaders()
1654
+ )
1655
+ );
1656
+ }
1657
+
1658
+ /**
1659
+ * This method writes a blob by specifying the list of block IDs that make up the
1660
+ * blob. In order to be written as part of a blob, a block must have been
1661
+ * successfully written to the server in a prior createBlobBlock method.
1662
+ *
1663
+ * You can call Put Block List to update a blob by uploading only those blocks
1664
+ * that have changed, then committing the new and existing blocks together.
1665
+ * You can do this by specifying whether to commit a block from the committed
1666
+ * block list or from the uncommitted block list, or to commit the most recently
1667
+ * uploaded version of the block, whichever list it may belong to.
1668
+ *
1669
+ * @param string $container The container name.
1670
+ * @param string $blob The blob name.
1671
+ * @param Models\BlockList|array $blockList The block entries.
1672
+ * @param Models\CommitBlobBlocksOptions $options The optional parameters.
1673
+ *
1674
+ * @return CopyBlobResult
1675
+ *
1676
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179467.aspx
1677
+ */
1678
+ public function commitBlobBlocks($container, $blob, $blockList, $options = null)
1679
+ {
1680
+ Validate::isString($container, 'container');
1681
+ Validate::isString($blob, 'blob');
1682
+ Validate::notNullOrEmpty($blob, 'blob');
1683
+ Validate::isTrue(
1684
+ $blockList instanceof BlockList || is_array($blockList),
1685
+ sprintf(
1686
+ Resources::INVALID_PARAM_MSG,
1687
+ 'blockList',
1688
+ get_class(new BlockList())
1689
+ )
1690
+ );
1691
+
1692
+ $method = Resources::HTTP_PUT;
1693
+ $headers = array();
1694
+ $postParams = array();
1695
+ $queryParams = array();
1696
+ $path = $this->_createPath($container, $blob);
1697
+ $statusCode = Resources::STATUS_CREATED;
1698
+ $isArray = is_array($blockList);
1699
+ $blockList = $isArray ? BlockList::create($blockList) : $blockList;
1700
+ $body = $blockList->toXml($this->dataSerializer);
1701
+
1702
+ if (is_null($options)) {
1703
+ $options = new CommitBlobBlocksOptions();
1704
+ }
1705
+
1706
+ $blobContentType = $options->getBlobContentType();
1707
+ $blobContentEncoding = $options->getBlobContentEncoding();
1708
+ $blobContentLanguage = $options->getBlobContentLanguage();
1709
+ $blobContentMD5 = $options->getBlobContentMD5();
1710
+ $blobCacheControl = $options->getBlobCacheControl();
1711
+ $leaseId = $options->getLeaseId();
1712
+ $contentType = Resources::URL_ENCODED_CONTENT_TYPE;
1713
+
1714
+ $metadata = $options->getMetadata();
1715
+ $headers = $this->generateMetadataHeaders($metadata);
1716
+ $headers = $this->addOptionalAccessConditionHeader(
1717
+ $headers,
1718
+ $options->getAccessCondition()
1719
+ );
1720
+
1721
+ $this->addOptionalHeader(
1722
+ $headers,
1723
+ Resources::X_MS_LEASE_ID,
1724
+ $leaseId
1725
+ );
1726
+ $this->addOptionalHeader(
1727
+ $headers,
1728
+ Resources::X_MS_BLOB_CACHE_CONTROL,
1729
+ $blobCacheControl
1730
+ );
1731
+ $this->addOptionalHeader(
1732
+ $headers,
1733
+ Resources::X_MS_BLOB_CONTENT_TYPE,
1734
+ $blobContentType
1735
+ );
1736
+ $this->addOptionalHeader(
1737
+ $headers,
1738
+ Resources::X_MS_BLOB_CONTENT_ENCODING,
1739
+ $blobContentEncoding
1740
+ );
1741
+ $this->addOptionalHeader(
1742
+ $headers,
1743
+ Resources::X_MS_BLOB_CONTENT_LANGUAGE,
1744
+ $blobContentLanguage
1745
+ );
1746
+ $this->addOptionalHeader(
1747
+ $headers,
1748
+ Resources::X_MS_BLOB_CONTENT_MD5,
1749
+ $blobContentMD5
1750
+ );
1751
+ $this->addOptionalHeader(
1752
+ $headers,
1753
+ Resources::CONTENT_TYPE,
1754
+ $contentType
1755
+ );
1756
+
1757
+ $this->addOptionalQueryParam(
1758
+ $queryParams,
1759
+ Resources::QP_TIMEOUT,
1760
+ $options->getTimeout()
1761
+ );
1762
+ $this->addOptionalQueryParam(
1763
+ $queryParams,
1764
+ Resources::QP_COMP,
1765
+ 'blocklist'
1766
+ );
1767
+
1768
+ return $this->send(
1769
+ $method,
1770
+ $headers,
1771
+ $queryParams,
1772
+ $postParams,
1773
+ $path,
1774
+ $statusCode,
1775
+ $body
1776
+ );
1777
+ }
1778
+
1779
+ /**
1780
+ * Retrieves the list of blocks that have been uploaded as part of a block blob.
1781
+ *
1782
+ * There are two block lists maintained for a blob:
1783
+ * 1) Committed Block List: The list of blocks that have been successfully
1784
+ * committed to a given blob with commitBlobBlocks.
1785
+ * 2) Uncommitted Block List: The list of blocks that have been uploaded for a
1786
+ * blob using Put Block (REST API), but that have not yet been committed.
1787
+ * These blocks are stored in Windows Azure in association with a blob, but do
1788
+ * not yet form part of the blob.
1789
+ *
1790
+ * @param string $container name of the container
1791
+ * @param string $blob name of the blob
1792
+ * @param Models\ListBlobBlocksOptions $options optional parameters
1793
+ *
1794
+ * @return Models\ListBlobBlocksResult
1795
+ *
1796
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179400.aspx
1797
+ */
1798
+ public function listBlobBlocks($container, $blob, $options = null)
1799
+ {
1800
+ Validate::isString($container, 'container');
1801
+ Validate::isString($blob, 'blob');
1802
+ Validate::notNullOrEmpty($blob, 'blob');
1803
+
1804
+ $method = Resources::HTTP_GET;
1805
+ $headers = array();
1806
+ $postParams = array();
1807
+ $queryParams = array();
1808
+ $path = $this->_createPath($container, $blob);
1809
+ $statusCode = Resources::STATUS_OK;
1810
+
1811
+ if (is_null($options)) {
1812
+ $options = new ListBlobBlocksOptions();
1813
+ }
1814
+
1815
+ $this->addOptionalHeader(
1816
+ $headers,
1817
+ Resources::X_MS_LEASE_ID,
1818
+ $options->getLeaseId()
1819
+ );
1820
+
1821
+ $this->addOptionalQueryParam(
1822
+ $queryParams,
1823
+ Resources::QP_TIMEOUT,
1824
+ $options->getTimeout()
1825
+ );
1826
+ $this->addOptionalQueryParam(
1827
+ $queryParams,
1828
+ Resources::QP_BLOCK_LIST_TYPE,
1829
+ $options->getBlockListType()
1830
+ );
1831
+ $this->addOptionalQueryParam(
1832
+ $queryParams,
1833
+ Resources::QP_SNAPSHOT,
1834
+ $options->getSnapshot()
1835
+ );
1836
+ $this->addOptionalQueryParam(
1837
+ $queryParams,
1838
+ Resources::QP_COMP,
1839
+ 'blocklist'
1840
+ );
1841
+
1842
+ $response = $this->send(
1843
+ $method,
1844
+ $headers,
1845
+ $queryParams,
1846
+ $postParams,
1847
+ $path,
1848
+ $statusCode
1849
+ );
1850
+
1851
+ $parsed = $this->dataSerializer->unserialize($response->getBody());
1852
+
1853
+ return ListBlobBlocksResult::create(HttpFormatter::formatHeaders($response->getHeaders()), $parsed);
1854
+ }
1855
+
1856
+ /**
1857
+ * Returns all properties and metadata on the blob.
1858
+ *
1859
+ * @param string $container name of the container
1860
+ * @param string $blob name of the blob
1861
+ * @param Models\GetBlobPropertiesOptions $options optional parameters
1862
+ *
1863
+ * @return Models\GetBlobPropertiesResult
1864
+ *
1865
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179394.aspx
1866
+ */
1867
+ public function getBlobProperties($container, $blob, $options = null)
1868
+ {
1869
+ Validate::isString($container, 'container');
1870
+ Validate::isString($blob, 'blob');
1871
+ Validate::notNullOrEmpty($blob, 'blob');
1872
+
1873
+ $method = Resources::HTTP_HEAD;
1874
+ $headers = array();
1875
+ $postParams = array();
1876
+ $queryParams = array();
1877
+ $path = $this->_createPath($container, $blob);
1878
+ $statusCode = Resources::STATUS_OK;
1879
+
1880
+ if (is_null($options)) {
1881
+ $options = new GetBlobPropertiesOptions();
1882
+ }
1883
+
1884
+ $headers = $this->addOptionalAccessConditionHeader(
1885
+ $headers,
1886
+ $options->getAccessCondition()
1887
+ );
1888
+
1889
+ $this->addOptionalHeader(
1890
+ $headers,
1891
+ Resources::X_MS_LEASE_ID,
1892
+ $options->getLeaseId()
1893
+ );
1894
+ $this->addOptionalQueryParam(
1895
+ $queryParams,
1896
+ Resources::QP_SNAPSHOT,
1897
+ $options->getSnapshot()
1898
+ );
1899
+ $this->addOptionalQueryParam(
1900
+ $queryParams,
1901
+ Resources::QP_TIMEOUT,
1902
+ $options->getTimeout()
1903
+ );
1904
+
1905
+ $response = $this->send(
1906
+ $method,
1907
+ $headers,
1908
+ $queryParams,
1909
+ $postParams,
1910
+ $path,
1911
+ $statusCode
1912
+ );
1913
+
1914
+ $headers = $response->getHeaders();
1915
+ $formattedHeaders = HttpFormatter::formatHeaders($headers);
1916
+
1917
+ return $this->_getBlobPropertiesResultFromResponse($formattedHeaders);
1918
+ }
1919
+
1920
+ /**
1921
+ * Returns all properties and metadata on the blob.
1922
+ *
1923
+ * @param string $container name of the container
1924
+ * @param string $blob name of the blob
1925
+ * @param Models\GetBlobMetadataOptions $options optional parameters
1926
+ *
1927
+ * @return Models\GetBlobMetadataResult
1928
+ *
1929
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179350.aspx
1930
+ */
1931
+ public function getBlobMetadata($container, $blob, $options = null)
1932
+ {
1933
+ Validate::isString($container, 'container');
1934
+ Validate::isString($blob, 'blob');
1935
+ Validate::notNullOrEmpty($blob, 'blob');
1936
+
1937
+ $method = Resources::HTTP_HEAD;
1938
+ $headers = array();
1939
+ $postParams = array();
1940
+ $queryParams = array();
1941
+ $path = $this->_createPath($container, $blob);
1942
+ $statusCode = Resources::STATUS_OK;
1943
+
1944
+ if (is_null($options)) {
1945
+ $options = new GetBlobMetadataOptions();
1946
+ }
1947
+
1948
+ $headers = $this->addOptionalAccessConditionHeader(
1949
+ $headers,
1950
+ $options->getAccessCondition()
1951
+ );
1952
+
1953
+ $this->addOptionalHeader(
1954
+ $headers,
1955
+ Resources::X_MS_LEASE_ID,
1956
+ $options->getLeaseId()
1957
+ );
1958
+ $this->addOptionalQueryParam(
1959
+ $queryParams,
1960
+ Resources::QP_SNAPSHOT,
1961
+ $options->getSnapshot()
1962
+ );
1963
+ $this->addOptionalQueryParam(
1964
+ $queryParams,
1965
+ Resources::QP_TIMEOUT,
1966
+ $options->getTimeout()
1967
+ );
1968
+ $this->addOptionalQueryParam(
1969
+ $queryParams,
1970
+ Resources::QP_COMP,
1971
+ 'metadata'
1972
+ );
1973
+
1974
+ $response = $this->send(
1975
+ $method,
1976
+ $headers,
1977
+ $queryParams,
1978
+ $postParams,
1979
+ $path,
1980
+ $statusCode
1981
+ );
1982
+ $responseHeaders = HttpFormatter::formatHeaders($response->getHeaders());
1983
+ $metadata = $this->getMetadataArray($responseHeaders);
1984
+
1985
+ return GetBlobMetadataResult::create($responseHeaders, $metadata);
1986
+ }
1987
+
1988
+ /**
1989
+ * Returns a list of active page ranges for a page blob. Active page ranges are
1990
+ * those that have been populated with data.
1991
+ *
1992
+ * @param string $container name of the container
1993
+ * @param string $blob name of the blob
1994
+ * @param Models\ListPageBlobRangesOptions $options optional parameters
1995
+ *
1996
+ * @return Models\ListPageBlobRangesResult
1997
+ *
1998
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691973.aspx
1999
+ */
2000
+ public function listPageBlobRanges($container, $blob, $options = null)
2001
+ {
2002
+ Validate::isString($container, 'container');
2003
+ Validate::isString($blob, 'blob');
2004
+ Validate::notNullOrEmpty($blob, 'blob');
2005
+
2006
+ $method = Resources::HTTP_GET;
2007
+ $headers = array();
2008
+ $queryParams = array();
2009
+ $postParams = array();
2010
+ $path = $this->_createPath($container, $blob);
2011
+ $statusCode = Resources::STATUS_OK;
2012
+
2013
+ if (is_null($options)) {
2014
+ $options = new ListPageBlobRangesOptions();
2015
+ }
2016
+
2017
+ $headers = $this->addOptionalAccessConditionHeader(
2018
+ $headers,
2019
+ $options->getAccessCondition()
2020
+ );
2021
+
2022
+ $headers = $this->_addOptionalRangeHeader(
2023
+ $headers,
2024
+ $options->getRangeStart(),
2025
+ $options->getRangeEnd()
2026
+ );
2027
+
2028
+ $this->addOptionalHeader(
2029
+ $headers,
2030
+ Resources::X_MS_LEASE_ID,
2031
+ $options->getLeaseId()
2032
+ );
2033
+ $this->addOptionalQueryParam(
2034
+ $queryParams,
2035
+ Resources::QP_SNAPSHOT,
2036
+ $options->getSnapshot()
2037
+ );
2038
+ $this->addOptionalQueryParam(
2039
+ $queryParams,
2040
+ Resources::QP_TIMEOUT,
2041
+ $options->getTimeout()
2042
+ );
2043
+ $this->addOptionalQueryParam(
2044
+ $queryParams,
2045
+ Resources::QP_COMP,
2046
+ 'pagelist'
2047
+ );
2048
+
2049
+ $response = $this->send(
2050
+ $method,
2051
+ $headers,
2052
+ $queryParams,
2053
+ $postParams,
2054
+ $path,
2055
+ $statusCode
2056
+ );
2057
+ $parsed = $this->dataSerializer->unserialize($response->getBody());
2058
+
2059
+ return ListPageBlobRangesResult::create(HttpFormatter::formatHeaders($response->getHeaders()), $parsed);
2060
+ }
2061
+
2062
+ /**
2063
+ * Sets system properties defined for a blob.
2064
+ *
2065
+ * @param string $container name of the container
2066
+ * @param string $blob name of the blob
2067
+ * @param Models\SetBlobPropertiesOptions $options optional parameters
2068
+ *
2069
+ * @return Models\SetBlobPropertiesResult
2070
+ *
2071
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691966.aspx
2072
+ */
2073
+ public function setBlobProperties($container, $blob, $options = null)
2074
+ {
2075
+ Validate::isString($container, 'container');
2076
+ Validate::isString($blob, 'blob');
2077
+ Validate::notNullOrEmpty($blob, 'blob');
2078
+
2079
+ $method = Resources::HTTP_PUT;
2080
+ $headers = array();
2081
+ $postParams = array();
2082
+ $queryParams = array();
2083
+ $path = $this->_createPath($container, $blob);
2084
+ $statusCode = Resources::STATUS_OK;
2085
+
2086
+ if (is_null($options)) {
2087
+ $options = new SetBlobPropertiesOptions();
2088
+ }
2089
+
2090
+ $blobContentType = $options->getBlobContentType();
2091
+ $blobContentEncoding = $options->getBlobContentEncoding();
2092
+ $blobContentLanguage = $options->getBlobContentLanguage();
2093
+ $blobContentLength = $options->getBlobContentLength();
2094
+ $blobContentMD5 = $options->getBlobContentMD5();
2095
+ $blobCacheControl = $options->getBlobCacheControl();
2096
+ $leaseId = $options->getLeaseId();
2097
+ $sNumberAction = $options->getSequenceNumberAction();
2098
+ $sNumber = $options->getSequenceNumber();
2099
+
2100
+ $headers = $this->addOptionalAccessConditionHeader(
2101
+ $headers,
2102
+ $options->getAccessCondition()
2103
+ );
2104
+
2105
+ $this->addOptionalHeader(
2106
+ $headers,
2107
+ Resources::X_MS_LEASE_ID,
2108
+ $leaseId
2109
+ );
2110
+ $this->addOptionalHeader(
2111
+ $headers,
2112
+ Resources::X_MS_BLOB_CACHE_CONTROL,
2113
+ $blobCacheControl
2114
+ );
2115
+ $this->addOptionalHeader(
2116
+ $headers,
2117
+ Resources::X_MS_BLOB_CONTENT_TYPE,
2118
+ $blobContentType
2119
+ );
2120
+ $this->addOptionalHeader(
2121
+ $headers,
2122
+ Resources::X_MS_BLOB_CONTENT_ENCODING,
2123
+ $blobContentEncoding
2124
+ );
2125
+ $this->addOptionalHeader(
2126
+ $headers,
2127
+ Resources::X_MS_BLOB_CONTENT_LANGUAGE,
2128
+ $blobContentLanguage
2129
+ );
2130
+ $this->addOptionalHeader(
2131
+ $headers,
2132
+ Resources::X_MS_BLOB_CONTENT_LENGTH,
2133
+ $blobContentLength
2134
+ );
2135
+ $this->addOptionalHeader(
2136
+ $headers,
2137
+ Resources::X_MS_BLOB_CONTENT_MD5,
2138
+ $blobContentMD5
2139
+ );
2140
+ $this->addOptionalHeader(
2141
+ $headers,
2142
+ Resources::X_MS_BLOB_SEQUENCE_NUMBER_ACTION,
2143
+ $sNumberAction
2144
+ );
2145
+ $this->addOptionalHeader(
2146
+ $headers,
2147
+ Resources::X_MS_BLOB_SEQUENCE_NUMBER,
2148
+ $sNumber
2149
+ );
2150
+
2151
+ $this->addOptionalQueryParam($queryParams, Resources::QP_COMP, 'properties');
2152
+ $this->addOptionalQueryParam(
2153
+ $queryParams,
2154
+ Resources::QP_TIMEOUT,
2155
+ $options->getTimeout()
2156
+ );
2157
+
2158
+ $response = $this->send(
2159
+ $method,
2160
+ $headers,
2161
+ $queryParams,
2162
+ $postParams,
2163
+ $path,
2164
+ $statusCode
2165
+ );
2166
+
2167
+ return SetBlobPropertiesResult::create(HttpFormatter::formatHeaders($response->getHeaders()));
2168
+ }
2169
+
2170
+ /**
2171
+ * Sets metadata headers on the blob.
2172
+ *
2173
+ * @param string $container name of the container
2174
+ * @param string $blob name of the blob
2175
+ * @param array $metadata key/value pair representation
2176
+ * @param Models\SetBlobMetadataOptions $options optional parameters
2177
+ *
2178
+ * @return Models\SetBlobMetadataResult
2179
+ *
2180
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179414.aspx
2181
+ */
2182
+ public function setBlobMetadata($container, $blob, $metadata, $options = null)
2183
+ {
2184
+ Validate::isString($container, 'container');
2185
+ Validate::isString($blob, 'blob');
2186
+ Validate::notNullOrEmpty($blob, 'blob');
2187
+ $this->validateMetadata($metadata);
2188
+
2189
+ $method = Resources::HTTP_PUT;
2190
+ $headers = array();
2191
+ $postParams = array();
2192
+ $queryParams = array();
2193
+ $path = $this->_createPath($container, $blob);
2194
+ $statusCode = Resources::STATUS_OK;
2195
+
2196
+ if (is_null($options)) {
2197
+ $options = new SetBlobMetadataOptions();
2198
+ }
2199
+
2200
+ $headers = $this->addOptionalAccessConditionHeader(
2201
+ $headers,
2202
+ $options->getAccessCondition()
2203
+ );
2204
+ $headers = $this->addMetadataHeaders($headers, $metadata);
2205
+
2206
+ $this->addOptionalHeader(
2207
+ $headers,
2208
+ Resources::X_MS_LEASE_ID,
2209
+ $options->getLeaseId()
2210
+ );
2211
+ $this->addOptionalQueryParam(
2212
+ $queryParams,
2213
+ Resources::QP_TIMEOUT,
2214
+ $options->getTimeout()
2215
+ );
2216
+ $this->addOptionalQueryParam(
2217
+ $queryParams,
2218
+ Resources::QP_COMP,
2219
+ 'metadata'
2220
+ );
2221
+
2222
+ $response = $this->send(
2223
+ $method,
2224
+ $headers,
2225
+ $queryParams,
2226
+ $postParams,
2227
+ $path,
2228
+ $statusCode
2229
+ );
2230
+
2231
+ return SetBlobMetadataResult::create(HttpFormatter::formatHeaders($response->getHeaders()));
2232
+ }
2233
+
2234
+ /**
2235
+ * Downloads a blob to a file, the result contains its metadata and
2236
+ * properties. The result will not contain a stream pointing to the
2237
+ * content of the file.
2238
+ *
2239
+ * @param string $path The path and name of the file
2240
+ * @param string $container name of the container
2241
+ * @param string $blob name of the blob
2242
+ * @param Models\GetBlobOptions $options optional parameters
2243
+ *
2244
+ * @return Models\GetBlobResult
2245
+ *
2246
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179440.aspx
2247
+ */
2248
+ public function saveBlobToFile($path, $container, $blob, $options = null)
2249
+ {
2250
+
2251
+ $resource = fopen($path, 'w+');
2252
+ if ($resource == null) {
2253
+ throw new \Exception(Resources::ERROR_FILE_COULD_NOT_BE_OPENED);
2254
+ }
2255
+
2256
+ $result = $this->getBlob($container, $blob, $options);
2257
+
2258
+ $content = $result->getContentStream();
2259
+
2260
+ while (!feof($content)) {
2261
+ fwrite($resource, stream_get_contents($content, Resources::MB_IN_BYTES_4));
2262
+ }
2263
+ //response body has already been set to file. Set the stream of the
2264
+ //response body to be null, then close the file.
2265
+ $result->setContentStream(null);
2266
+ fclose($resource);
2267
+
2268
+ return $result;
2269
+ }
2270
+
2271
+ /**
2272
+ * Reads or downloads a blob from the system, including its metadata and
2273
+ * properties.
2274
+ *
2275
+ * @param string $container name of the container
2276
+ * @param string $blob name of the blob
2277
+ * @param Models\GetBlobOptions $options optional parameters
2278
+ *
2279
+ * @return Models\GetBlobResult
2280
+ *
2281
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179440.aspx
2282
+ */
2283
+ public function getBlob($container, $blob, $options = null)
2284
+ {
2285
+ Validate::isString($container, 'container');
2286
+ Validate::isString($blob, 'blob');
2287
+
2288
+ $method = Resources::HTTP_GET;
2289
+ $headers = array();
2290
+ $postParams = array();
2291
+ $queryParams = array();
2292
+ $path = $this->_createPath($container, $blob);
2293
+ $statusCode = array(
2294
+ Resources::STATUS_OK,
2295
+ Resources::STATUS_PARTIAL_CONTENT
2296
+ );
2297
+
2298
+ if (is_null($options)) {
2299
+ $options = new GetBlobOptions();
2300
+ }
2301
+
2302
+ $getMD5 = $options->getComputeRangeMD5();
2303
+ $headers = $this->addOptionalAccessConditionHeader(
2304
+ $headers,
2305
+ $options->getAccessCondition()
2306
+ );
2307
+ $headers = $this->_addOptionalRangeHeader(
2308
+ $headers,
2309
+ $options->getRangeStart(),
2310
+ $options->getRangeEnd()
2311
+ );
2312
+
2313
+ $this->addOptionalHeader(
2314
+ $headers,
2315
+ Resources::X_MS_LEASE_ID,
2316
+ $options->getLeaseId()
2317
+ );
2318
+ $this->addOptionalHeader(
2319
+ $headers,
2320
+ Resources::X_MS_RANGE_GET_CONTENT_MD5,
2321
+ $getMD5 ? 'true' : null
2322
+ );
2323
+ $this->addOptionalQueryParam(
2324
+ $queryParams,
2325
+ Resources::QP_TIMEOUT,
2326
+ $options->getTimeout()
2327
+ );
2328
+ $this->addOptionalQueryParam(
2329
+ $queryParams,
2330
+ Resources::QP_SNAPSHOT,
2331
+ $options->getSnapshot()
2332
+ );
2333
+
2334
+ $response = $this->send(
2335
+ $method,
2336
+ $headers,
2337
+ $queryParams,
2338
+ $postParams,
2339
+ $path,
2340
+ $statusCode,
2341
+ Resources::EMPTY_STRING,
2342
+ ['stream' => true] //setting stream to true to enable streaming
2343
+ );
2344
+
2345
+ $metadata = $this->getMetadataArray(HttpFormatter::formatHeaders($response->getHeaders()));
2346
+
2347
+ return GetBlobResult::create(
2348
+ HttpFormatter::formatHeaders($response->getHeaders()),
2349
+ $response->getBody(),
2350
+ $metadata
2351
+ );
2352
+ }
2353
+
2354
+ /**
2355
+ * Deletes a blob or blob snapshot.
2356
+ *
2357
+ * Note that if the snapshot entry is specified in the $options then only this
2358
+ * blob snapshot is deleted. To delete all blob snapshots, do not set Snapshot
2359
+ * and just set getDeleteSnaphotsOnly to true.
2360
+ *
2361
+ * @param string $container name of the container
2362
+ * @param string $blob name of the blob
2363
+ * @param Models\DeleteBlobOptions $options optional parameters
2364
+ *
2365
+ * @return none
2366
+ *
2367
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179413.aspx
2368
+ */
2369
+ public function deleteBlob($container, $blob, $options = null)
2370
+ {
2371
+ Validate::isString($container, 'container');
2372
+ Validate::isString($blob, 'blob');
2373
+ Validate::notNullOrEmpty($blob, 'blob');
2374
+
2375
+ $method = Resources::HTTP_DELETE;
2376
+ $headers = array();
2377
+ $postParams = array();
2378
+ $queryParams = array();
2379
+ $path = $this->_createPath($container, $blob);
2380
+ $statusCode = Resources::STATUS_ACCEPTED;
2381
+
2382
+ if (is_null($options)) {
2383
+ $options = new DeleteBlobOptions();
2384
+ }
2385
+
2386
+ if (is_null($options->getSnapshot())) {
2387
+ $delSnapshots = $options->getDeleteSnaphotsOnly() ? 'only' : 'include';
2388
+ $this->addOptionalHeader(
2389
+ $headers,
2390
+ Resources::X_MS_DELETE_SNAPSHOTS,
2391
+ $delSnapshots
2392
+ );
2393
+ } else {
2394
+ $this->addOptionalQueryParam(
2395
+ $queryParams,
2396
+ Resources::QP_SNAPSHOT,
2397
+ $options->getSnapshot()
2398
+ );
2399
+ }
2400
+
2401
+ $headers = $this->addOptionalAccessConditionHeader(
2402
+ $headers,
2403
+ $options->getAccessCondition()
2404
+ );
2405
+
2406
+ $this->addOptionalHeader(
2407
+ $headers,
2408
+ Resources::X_MS_LEASE_ID,
2409
+ $options->getLeaseId()
2410
+ );
2411
+
2412
+ $this->addOptionalQueryParam(
2413
+ $queryParams,
2414
+ Resources::QP_TIMEOUT,
2415
+ $options->getTimeout()
2416
+ );
2417
+
2418
+ $this->send(
2419
+ $method,
2420
+ $headers,
2421
+ $queryParams,
2422
+ $postParams,
2423
+ $path,
2424
+ $statusCode
2425
+ );
2426
+ }
2427
+
2428
+ /**
2429
+ * Creates a snapshot of a blob.
2430
+ *
2431
+ * @param string $container The name of the container.
2432
+ * @param string $blob The name of the blob.
2433
+ * @param Models\CreateBlobSnapshotOptions $options The optional parameters.
2434
+ *
2435
+ * @return Models\CreateBlobSnapshotResult
2436
+ *
2437
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691971.aspx
2438
+ */
2439
+ public function createBlobSnapshot($container, $blob, $options = null)
2440
+ {
2441
+ Validate::isString($container, 'container');
2442
+ Validate::isString($blob, 'blob');
2443
+ Validate::notNullOrEmpty($blob, 'blob');
2444
+
2445
+ $method = Resources::HTTP_PUT;
2446
+ $headers = array();
2447
+ $postParams = array();
2448
+ $queryParams = array();
2449
+ $path = $this->_createPath($container, $blob);
2450
+ $expectedStatusCode = Resources::STATUS_CREATED;
2451
+
2452
+ if (is_null($options)) {
2453
+ $options = new CreateBlobSnapshotOptions();
2454
+ }
2455
+
2456
+ $queryParams[Resources::QP_COMP] = 'snapshot';
2457
+ $this->addOptionalQueryParam(
2458
+ $queryParams,
2459
+ Resources::QP_TIMEOUT,
2460
+ $options->getTimeout()
2461
+ );
2462
+
2463
+ $headers = $this->addOptionalAccessConditionHeader(
2464
+ $headers,
2465
+ $options->getAccessCondition()
2466
+ );
2467
+ $headers = $this->addMetadataHeaders($headers, $options->getMetadata());
2468
+ $this->addOptionalHeader(
2469
+ $headers,
2470
+ Resources::X_MS_LEASE_ID,
2471
+ $options->getLeaseId()
2472
+ );
2473
+
2474
+ $response = $this->send(
2475
+ $method,
2476
+ $headers,
2477
+ $queryParams,
2478
+ $postParams,
2479
+ $path,
2480
+ $expectedStatusCode
2481
+ );
2482
+
2483
+ return CreateBlobSnapshotResult::create(HttpFormatter::formatHeaders($response->getHeaders()));
2484
+ }
2485
+
2486
+ /**
2487
+ * Copies a source blob to a destination blob within the same storage account.
2488
+ *
2489
+ * @param string $destinationContainer name of the destination
2490
+ * container
2491
+ * @param string $destinationBlob name of the destination
2492
+ * blob
2493
+ * @param string $sourceContainer name of the source
2494
+ * container
2495
+ * @param string $sourceBlob name of the source
2496
+ * blob
2497
+ * @param Models\CopyBlobOptions $options optional parameters
2498
+ *
2499
+ * @return CopyBlobResult
2500
+ *
2501
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd894037.aspx
2502
+ */
2503
+ public function copyBlob(
2504
+ $destinationContainer,
2505
+ $destinationBlob,
2506
+ $sourceContainer,
2507
+ $sourceBlob,
2508
+ $options = null
2509
+ ) {
2510
+
2511
+ $method = Resources::HTTP_PUT;
2512
+ $headers = array();
2513
+ $postParams = array();
2514
+ $queryParams = array();
2515
+ $destinationBlobPath = $this->_createPath(
2516
+ $destinationContainer,
2517
+ $destinationBlob
2518
+ );
2519
+ $statusCode = Resources::STATUS_ACCEPTED;
2520
+
2521
+ if (is_null($options)) {
2522
+ $options = new CopyBlobOptions();
2523
+ }
2524
+
2525
+ $this->addOptionalQueryParam(
2526
+ $queryParams,
2527
+ Resources::QP_TIMEOUT,
2528
+ $options->getTimeout()
2529
+ );
2530
+
2531
+ $sourceBlobPath = $this->_getCopyBlobSourceName(
2532
+ $sourceContainer,
2533
+ $sourceBlob,
2534
+ $options
2535
+ );
2536
+
2537
+ $headers = $this->addOptionalAccessConditionHeader(
2538
+ $headers,
2539
+ $options->getAccessCondition()
2540
+ );
2541
+
2542
+ $headers = $this->addOptionalSourceAccessConditionHeader(
2543
+ $headers,
2544
+ $options->getSourceAccessCondition()
2545
+ );
2546
+
2547
+ $this->addOptionalHeader(
2548
+ $headers,
2549
+ Resources::X_MS_COPY_SOURCE,
2550
+ $sourceBlobPath
2551
+ );
2552
+
2553
+ $headers = $this->addMetadataHeaders($headers, $options->getMetadata());
2554
+
2555
+ $this->addOptionalHeader(
2556
+ $headers,
2557
+ Resources::X_MS_LEASE_ID,
2558
+ $options->getLeaseId()
2559
+ );
2560
+
2561
+ $this->addOptionalHeader(
2562
+ $headers,
2563
+ Resources::X_MS_SOURCE_LEASE_ID,
2564
+ $options->getSourceLeaseId()
2565
+ );
2566
+
2567
+ $response = $this->send(
2568
+ $method,
2569
+ $headers,
2570
+ $queryParams,
2571
+ $postParams,
2572
+ $destinationBlobPath,
2573
+ $statusCode
2574
+ );
2575
+
2576
+ return CopyBlobResult::create(HttpFormatter::formatHeaders($response->getHeaders()));
2577
+ }
2578
+
2579
+ /**
2580
+ * Establishes an exclusive one-minute write lock on a blob. To write to a locked
2581
+ * blob, a client must provide a lease ID.
2582
+ *
2583
+ * @param string $container name of the container
2584
+ * @param string $blob name of the blob
2585
+ * @param Models\AcquireLeaseOptions $options optional parameters
2586
+ *
2587
+ * @return Models\AcquireLeaseResult
2588
+ *
2589
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691972.aspx
2590
+ */
2591
+ public function acquireLease($container, $blob, $options = null)
2592
+ {
2593
+ $headers = $this->_putLeaseImpl(
2594
+ LeaseMode::ACQUIRE_ACTION,
2595
+ $container,
2596
+ $blob,
2597
+ null /* leaseId */,
2598
+ is_null($options) ? new AcquireLeaseOptions() : $options,
2599
+ is_null($options) ? null : $options->getAccessCondition()
2600
+ );
2601
+
2602
+ return AcquireLeaseResult::create($headers);
2603
+ }
2604
+
2605
+ /**
2606
+ * Renews an existing lease
2607
+ *
2608
+ * @param string $container name of the container
2609
+ * @param string $blob name of the blob
2610
+ * @param string $leaseId lease id when acquiring
2611
+ * @param Models\BlobServiceOptions $options optional parameters
2612
+ *
2613
+ * @return Models\AcquireLeaseResult
2614
+ *
2615
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691972.aspx
2616
+ */
2617
+ public function renewLease($container, $blob, $leaseId, $options = null)
2618
+ {
2619
+ $headers = $this->_putLeaseImpl(
2620
+ LeaseMode::RENEW_ACTION,
2621
+ $container,
2622
+ $blob,
2623
+ $leaseId,
2624
+ is_null($options) ? new BlobServiceOptions() : $options
2625
+ );
2626
+
2627
+ return AcquireLeaseResult::create($headers);
2628
+ }
2629
+
2630
+ /**
2631
+ * Frees the lease if it is no longer needed so that another client may
2632
+ * immediately acquire a lease against the blob.
2633
+ *
2634
+ * @param string $container name of the container
2635
+ * @param string $blob name of the blob
2636
+ * @param string $leaseId lease id when acquiring
2637
+ * @param Models\BlobServiceOptions $options optional parameters
2638
+ *
2639
+ * @return none
2640
+ *
2641
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691972.aspx
2642
+ */
2643
+ public function releaseLease($container, $blob, $leaseId, $options = null)
2644
+ {
2645
+ $this->_putLeaseImpl(
2646
+ LeaseMode::RELEASE_ACTION,
2647
+ $container,
2648
+ $blob,
2649
+ $leaseId,
2650
+ is_null($options) ? new BlobServiceOptions() : $options
2651
+ );
2652
+ }
2653
+
2654
+ /**
2655
+ * Ends the lease but ensure that another client cannot acquire a new lease until
2656
+ * the current lease period has expired.
2657
+ *
2658
+ * @param string $container name of the container
2659
+ * @param string $blob name of the blob
2660
+ * @param Models\BlobServiceOptions $options optional parameters
2661
+ *
2662
+ * @return BreakLeaseResult
2663
+ *
2664
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691972.aspx
2665
+ */
2666
+ public function breakLease($container, $blob, $options = null)
2667
+ {
2668
+ $headers = $this->_putLeaseImpl(
2669
+ LeaseMode::BREAK_ACTION,
2670
+ $container,
2671
+ $blob,
2672
+ null,
2673
+ is_null($options) ? new BlobServiceOptions() : $options
2674
+ );
2675
+
2676
+ return BreakLeaseResult::create($headers);
2677
+ }
2678
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Internal/IBlob.php ADDED
@@ -0,0 +1,502 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Internal
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Internal;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\FilterableService;
28
+
29
+ /**
30
+ * This interface has all REST APIs provided by Windows Azure for Blob service.
31
+ *
32
+ * @category Microsoft
33
+ * @package MicrosoftAzure\Storage\Blob\Internal
34
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
35
+ * @copyright 2016 Microsoft Corporation
36
+ * @license https://github.com/azure/azure-storage-php/LICENSE
37
+ * @version Release: 0.11.0
38
+ * @link https://github.com/azure/azure-storage-php
39
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd135733.aspx
40
+ */
41
+ interface IBlob extends FilterableService
42
+ {
43
+ /**
44
+ * Gets the properties of the Blob service.
45
+ *
46
+ * @param Models\BlobServiceOptions $options optional blob service options.
47
+ *
48
+ * @return MicrosoftAzure\Storage\Common\Models\GetServicePropertiesResult
49
+ *
50
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/hh452239.aspx
51
+ */
52
+ public function getServiceProperties($options = null);
53
+
54
+ /**
55
+ * Sets the properties of the Blob service.
56
+ *
57
+ * @param ServiceProperties $serviceProperties new service properties
58
+ * @param Models\BlobServiceOptions $options optional parameters
59
+ *
60
+ * @return none.
61
+ *
62
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/hh452235.aspx
63
+ */
64
+ public function setServiceProperties($serviceProperties, $options = null);
65
+
66
+ /**
67
+ * Lists all of the containers in the given storage account.
68
+ *
69
+ * @param Models\ListContainersOptions $options optional parameters
70
+ *
71
+ * @return \MicrosoftAzure\Storage\Blob\Models\ListContainersResult
72
+ *
73
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179352.aspx
74
+ */
75
+ public function listContainers($options = null);
76
+
77
+ /**
78
+ * Creates a new container in the given storage account.
79
+ *
80
+ * @param string $container name
81
+ * @param Models\CreateContainerOptions $options optional parameters
82
+ *
83
+ * @return none.
84
+ *
85
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179468.aspx
86
+ */
87
+ public function createContainer($container, $options = null);
88
+
89
+ /**
90
+ * Creates a new container in the given storage account.
91
+ *
92
+ * @param string $container name
93
+ * @param Models\DeleteContainerOptions $options optional parameters
94
+ *
95
+ * @return none.
96
+ *
97
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179408.aspx
98
+ */
99
+ public function deleteContainer($container, $options = null);
100
+
101
+ /**
102
+ * Returns all properties and metadata on the container.
103
+ *
104
+ * @param string $container name
105
+ * @param Models\BlobServiceOptions $options optional parameters
106
+ *
107
+ * @return Models\GetContainerPropertiesResult
108
+ *
109
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179370.aspx
110
+ */
111
+ public function getContainerProperties($container, $options = null);
112
+
113
+ /**
114
+ * Returns only user-defined metadata for the specified container.
115
+ *
116
+ * @param string $container name
117
+ * @param Models\BlobServiceOptions $options optional parameters
118
+ *
119
+ * @return Models\GetContainerPropertiesResult
120
+ *
121
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691976.aspx
122
+ */
123
+ public function getContainerMetadata($container, $options = null);
124
+
125
+ /**
126
+ * Gets the access control list (ACL) and any container-level access policies
127
+ * for the container.
128
+ *
129
+ * @param string $container name
130
+ * @param Models\BlobServiceOptions $options optional parameters
131
+ *
132
+ * @return Models\GetContainerAclResult
133
+ *
134
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179469.aspx
135
+ */
136
+ public function getContainerAcl($container, $options = null);
137
+
138
+ /**
139
+ * Sets the ACL and any container-level access policies for the container.
140
+ *
141
+ * @param string $container name
142
+ * @param Models\ContainerAcl $acl access control list for container
143
+ * @param Models\BlobServiceOptions $options optional parameters
144
+ *
145
+ * @return none.
146
+ *
147
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179391.aspx
148
+ */
149
+ public function setContainerAcl($container, $acl, $options = null);
150
+
151
+ /**
152
+ * Sets metadata headers on the container.
153
+ *
154
+ * @param string $container name
155
+ * @param array $metadata metadata key/value pair.
156
+ * @param Models\SetContainerMetadataOptions $options optional parameters
157
+ *
158
+ * @return none.
159
+ *
160
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179362.aspx
161
+ */
162
+ public function setContainerMetadata($container, $metadata, $options = null);
163
+
164
+ /**
165
+ * Lists all of the blobs in the given container.
166
+ *
167
+ * @param string $container name
168
+ * @param Models\ListBlobsOptions $options optional parameters
169
+ *
170
+ * @return \MicrosoftAzure\Storage\Blob\Models\ListBlobsResult
171
+ *
172
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd135734.aspx
173
+ */
174
+ public function listBlobs($container, $options = null);
175
+
176
+ /**
177
+ * Creates a new page blob. Note that calling createPageBlob to create a page
178
+ * blob only initializes the blob.
179
+ * To add content to a page blob, call createBlobPages method.
180
+ *
181
+ * @param string $container name of the container
182
+ * @param string $blob name of the blob
183
+ * @param int $length specifies the maximum size for the
184
+ * page blob, up to 1 TB. The page blob size must be aligned to a 512-byte
185
+ * boundary.
186
+ * @param Models\CreateBlobOptions $options optional parameters
187
+ *
188
+ * @return CopyBlobResult
189
+ *
190
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179451.aspx
191
+ */
192
+ public function createPageBlob($container, $blob, $length, $options = null);
193
+
194
+ /**
195
+ * Creates a new block blob or updates the content of an existing block blob.
196
+ * Updating an existing block blob overwrites any existing metadata on the blob.
197
+ * Partial updates are not supported with createBlockBlob; the content of the
198
+ * existing blob is overwritten with the content of the new blob. To perform a
199
+ * partial update of the content of a block blob, use the createBlockList method.
200
+ *
201
+ * @param string $container name of the container
202
+ * @param string $blob name of the blob
203
+ * @param string $content content of the blob
204
+ * @param Models\CreateBlobOptions $options optional parameters
205
+ *
206
+ * @return CopyBlobResult
207
+ *
208
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179451.aspx
209
+ */
210
+ public function createBlockBlob($container, $blob, $content, $options = null);
211
+
212
+ /**
213
+ * Clears a range of pages from the blob.
214
+ *
215
+ * @param string $container name of the container
216
+ * @param string $blob name of the blob
217
+ * @param Models\PageRange $range Can be up to the value of the
218
+ * blob's full size.
219
+ * @param Models\CreateBlobPagesOptions $options optional parameters
220
+ *
221
+ * @return Models\CreateBlobPagesResult.
222
+ *
223
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691975.aspx
224
+ */
225
+ public function clearBlobPages($container, $blob, $range, $options = null);
226
+
227
+ /**
228
+ * Creates a range of pages to a page blob.
229
+ *
230
+ * @param string $container name of the container
231
+ * @param string $blob name of the blob
232
+ * @param Models\PageRange $range Can be up to 4 MB in size
233
+ * @param string $content the blob contents
234
+ * @param Models\CreateBlobPagesOptions $options optional parameters
235
+ *
236
+ * @return Models\CreateBlobPagesResult.
237
+ *
238
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691975.aspx
239
+ */
240
+ public function createBlobPages(
241
+ $container,
242
+ $blob,
243
+ $range,
244
+ $content,
245
+ $options = null
246
+ );
247
+
248
+ /**
249
+ * Creates a new block to be committed as part of a block blob.
250
+ *
251
+ * @param string $container name of the container
252
+ * @param string $blob name of the blob
253
+ * @param string $blockId must be less than or equal to
254
+ * 64 bytes in size. For a given blob, the length of the value specified for the
255
+ * blockid parameter must be the same size for each block.
256
+ * @param string $content the blob block contents
257
+ * @param Models\CreateBlobBlockOptions $options optional parameters
258
+ *
259
+ * @return none.
260
+ *
261
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd135726.aspx
262
+ */
263
+ public function createBlobBlock(
264
+ $container,
265
+ $blob,
266
+ $blockId,
267
+ $content,
268
+ $options = null
269
+ );
270
+
271
+ /**
272
+ * This method writes a blob by specifying the list of block IDs that make up the
273
+ * blob. In order to be written as part of a blob, a block must have been
274
+ * successfully written to the server in a prior createBlobBlock method.
275
+ *
276
+ * You can call Put Block List to update a blob by uploading only those blocks
277
+ * that have changed, then committing the new and existing blocks together.
278
+ * You can do this by specifying whether to commit a block from the committed
279
+ * block list or from the uncommitted block list, or to commit the most recently
280
+ * uploaded version of the block, whichever list it may belong to.
281
+ *
282
+ * @param string $container name of the container
283
+ * @param string $blob name of the blob
284
+ * @param Models\BlockList $blockList the block list entries
285
+ * @param Models\CommitBlobBlocksOptions $options optional parameters
286
+ *
287
+ * @return none.
288
+ *
289
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179467.aspx
290
+ */
291
+ public function commitBlobBlocks($container, $blob, $blockList, $options = null);
292
+
293
+ /**
294
+ * Retrieves the list of blocks that have been uploaded as part of a block blob.
295
+ *
296
+ * There are two block lists maintained for a blob:
297
+ * 1) Committed Block List: The list of blocks that have been successfully
298
+ * committed to a given blob with commitBlobBlocks.
299
+ * 2) Uncommitted Block List: The list of blocks that have been uploaded for a
300
+ * blob using Put Block (REST API), but that have not yet been committed.
301
+ * These blocks are stored in Windows Azure in association with a blob, but do
302
+ * not yet form part of the blob.
303
+ *
304
+ * @param string $container name of the container
305
+ * @param string $blob name of the blob
306
+ * @param Models\ListBlobBlocksOptions $options optional parameters
307
+ *
308
+ * @return Models\ListBlobBlocksResult
309
+ *
310
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179400.aspx
311
+ */
312
+ public function listBlobBlocks($container, $blob, $options = null);
313
+
314
+ /**
315
+ * Returns all properties and metadata on the blob.
316
+ *
317
+ * @param string $container name of the container
318
+ * @param string $blob name of the blob
319
+ * @param Models\GetBlobPropertiesOptions $options optional parameters
320
+ *
321
+ * @return Models\GetBlobPropertiesResult
322
+ *
323
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179394.aspx
324
+ */
325
+ public function getBlobProperties($container, $blob, $options = null);
326
+
327
+ /**
328
+ * Returns all properties and metadata on the blob.
329
+ *
330
+ * @param string $container name of the container
331
+ * @param string $blob name of the blob
332
+ * @param Models\GetBlobMetadataOptions $options optional parameters
333
+ *
334
+ * @return Models\GetBlobMetadataResult
335
+ *
336
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179350.aspx
337
+ */
338
+ public function getBlobMetadata($container, $blob, $options = null);
339
+
340
+ /**
341
+ * Returns a list of active page ranges for a page blob. Active page ranges are
342
+ * those that have been populated with data.
343
+ *
344
+ * @param string $container name of the container
345
+ * @param string $blob name of the blob
346
+ * @param Models\ListPageBlobRangesOptions $options optional parameters
347
+ *
348
+ * @return Models\ListPageBlobRangesResult
349
+ *
350
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691973.aspx
351
+ */
352
+ public function listPageBlobRanges($container, $blob, $options = null);
353
+
354
+ /**
355
+ * Sets system properties defined for a blob.
356
+ *
357
+ * @param string $container name of the container
358
+ * @param string $blob name of the blob
359
+ * @param Models\SetBlobPropertiesOptions $options optional parameters
360
+ *
361
+ * @return Models\SetBlobPropertiesResult
362
+ *
363
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691966.aspx
364
+ */
365
+ public function setBlobProperties($container, $blob, $options = null);
366
+
367
+ /**
368
+ * Sets metadata headers on the blob.
369
+ *
370
+ * @param string $container name of the container
371
+ * @param string $blob name of the blob
372
+ * @param array $metadata key/value pair representation
373
+ * @param Models\SetBlobMetadataOptions $options optional parameters
374
+ *
375
+ * @return Models\SetBlobMetadataResult
376
+ *
377
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179414.aspx
378
+ */
379
+ public function setBlobMetadata($container, $blob, $metadata, $options = null);
380
+
381
+ /**
382
+ * Reads or downloads a blob from the system, including its metadata and
383
+ * properties.
384
+ *
385
+ * @param string $container name of the container
386
+ * @param string $blob name of the blob
387
+ * @param Models\GetBlobOptions $options optional parameters
388
+ *
389
+ * @return Models\GetBlobResult
390
+ *
391
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179440.aspx
392
+ */
393
+ public function getBlob($container, $blob, $options = null);
394
+
395
+ /**
396
+ * Deletes a blob or blob snapshot.
397
+ *
398
+ * Note that if the snapshot entry is specified in the $options then only this
399
+ * blob snapshot is deleted. To delete all blob snapshots, do not set Snapshot
400
+ * and just set getDeleteSnaphotsOnly to true.
401
+ *
402
+ * @param string $container name of the container
403
+ * @param string $blob name of the blob
404
+ * @param Models\DeleteBlobOptions $options optional parameters
405
+ *
406
+ * @return none
407
+ *
408
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179413.aspx
409
+ */
410
+ public function deleteBlob($container, $blob, $options = null);
411
+
412
+ /**
413
+ * Creates a snapshot of a blob.
414
+ *
415
+ * @param string $container name of the container
416
+ * @param string $blob name of the blob
417
+ * @param Models\CreateBlobSnapshotOptions $options optional parameters
418
+ *
419
+ * @return Models\CreateBlobSnapshotResult
420
+ *
421
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691971.aspx
422
+ */
423
+ public function createBlobSnapshot($container, $blob, $options = null);
424
+
425
+ /**
426
+ * Copies a source blob to a destination blob within the same storage account.
427
+ *
428
+ * @param string $destinationContainer name of container
429
+ * @param string $destinationBlob name of blob
430
+ * @param string $sourceContainer name of container
431
+ * @param string $sourceBlob name of blob
432
+ * @param Models\CopyBlobOptions $options optional parameters
433
+ *
434
+ * @return CopyBlobResult
435
+ *
436
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd894037.aspx
437
+ */
438
+ public function copyBlob(
439
+ $destinationContainer,
440
+ $destinationBlob,
441
+ $sourceContainer,
442
+ $sourceBlob,
443
+ $options = null
444
+ );
445
+
446
+ /**
447
+ * Establishes an exclusive one-minute write lock on a blob. To write to a locked
448
+ * blob, a client must provide a lease ID.
449
+ *
450
+ * @param string $container name of the container
451
+ * @param string $blob name of the blob
452
+ * @param Models\AcquireLeaseOptions $options optional parameters
453
+ *
454
+ * @return Models\AcquireLeaseResult
455
+ *
456
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691972.aspx
457
+ */
458
+ public function acquireLease($container, $blob, $options = null);
459
+
460
+ /**
461
+ * Renews an existing lease
462
+ *
463
+ * @param string $container name of the container
464
+ * @param string $blob name of the blob
465
+ * @param string $leaseId lease id when acquiring
466
+ * @param Models\BlobServiceOptions $options optional parameters
467
+ *
468
+ * @return Models\AcquireLeaseResult
469
+ *
470
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691972.aspx
471
+ */
472
+ public function renewLease($container, $blob, $leaseId, $options = null);
473
+
474
+ /**
475
+ * Frees the lease if it is no longer needed so that another client may
476
+ * immediately acquire a lease against the blob.
477
+ *
478
+ * @param string $container name of the container
479
+ * @param string $blob name of the blob
480
+ * @param string $leaseId lease id when acquiring
481
+ * @param Models\BlobServiceOptions $options optional parameters
482
+ *
483
+ * @return none
484
+ *
485
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691972.aspx
486
+ */
487
+ public function releaseLease($container, $blob, $leaseId, $options = null);
488
+
489
+ /**
490
+ * Ends the lease but ensure that another client cannot acquire a new lease until
491
+ * the current lease period has expired.
492
+ *
493
+ * @param string $container name of the container
494
+ * @param string $blob name of the blob
495
+ * @param Models\BlobServiceOptions $options optional parameters
496
+ *
497
+ * @return none
498
+ *
499
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/ee691972.aspx
500
+ */
501
+ public function breakLease($container, $blob, $options = null);
502
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/AccessCondition.php ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
28
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
29
+ use MicrosoftAzure\Storage\Common\Internal\WindowsAzureUtilities;
30
+
31
+ /**
32
+ * Represents a set of access conditions to be used for operations against the
33
+ * storage services.
34
+ *
35
+ * @category Microsoft
36
+ * @package MicrosoftAzure\Storage\Blob\Models
37
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
38
+ * @copyright 2016 Microsoft Corporation
39
+ * @license https://github.com/azure/azure-storage-php/LICENSE
40
+ * @version Release: 0.11.0
41
+ * @link https://github.com/azure/azure-storage-php
42
+ */
43
+ class AccessCondition
44
+ {
45
+ /**
46
+ * Represents the header type.
47
+ *
48
+ * @var string
49
+ */
50
+ private $_header = Resources::EMPTY_STRING;
51
+
52
+ /**
53
+ * Represents the header value.
54
+ *
55
+ * @var string
56
+ */
57
+ private $_value;
58
+
59
+ /**
60
+ * Constructor
61
+ *
62
+ * @param string $headerType header name
63
+ * @param string $value header value
64
+ */
65
+ protected function __construct($headerType, $value)
66
+ {
67
+ $this->setHeader($headerType);
68
+ $this->setValue($value);
69
+ }
70
+
71
+ /**
72
+ * Specifies that no access condition is set.
73
+ *
74
+ * @return \MicrosoftAzure\Storage\Blob\Models\AccessCondition
75
+ */
76
+ public static function none()
77
+ {
78
+ return new AccessCondition(Resources::EMPTY_STRING, null);
79
+ }
80
+
81
+ /**
82
+ * Returns an access condition such that an operation will be performed only if
83
+ * the resource's ETag value matches the specified ETag value.
84
+ * <p>
85
+ * Setting this access condition modifies the request to include the HTTP
86
+ * <i>If-Match</i> conditional header. If this access condition is set, the
87
+ * operation is performed only if the ETag of the resource matches the specified
88
+ * ETag.
89
+ * <p>
90
+ * For more information, see
91
+ * <a href= 'http://go.microsoft.com/fwlink/?LinkID=224642&clcid=0x409'>
92
+ * Specifying Conditional Headers for Blob Service Operations</a>.
93
+ *
94
+ * @param string $etag a string that represents the ETag value to check.
95
+ *
96
+ * @return \MicrosoftAzure\Storage\Blob\Models\AccessCondition
97
+ */
98
+ public static function ifMatch($etag)
99
+ {
100
+ return new AccessCondition(Resources::IF_MATCH, $etag);
101
+ }
102
+
103
+ /**
104
+ * Returns an access condition such that an operation will be performed only if
105
+ * the resource has been modified since the specified time.
106
+ * <p>
107
+ * Setting this access condition modifies the request to include the HTTP
108
+ * <i>If-Modified-Since</i> conditional header. If this access condition is set,
109
+ * the operation is performed only if the resource has been modified since the
110
+ * specified time.
111
+ * <p>
112
+ * For more information, see
113
+ * <a href= 'http://go.microsoft.com/fwlink/?LinkID=224642&clcid=0x409'>
114
+ * Specifying Conditional Headers for Blob Service Operations</a>.
115
+ *
116
+ * @param \DateTime $lastModified date that represents the last-modified
117
+ * time to check for the resource.
118
+ *
119
+ * @return \MicrosoftAzure\Storage\Blob\Models\AccessCondition
120
+ */
121
+ public static function ifModifiedSince($lastModified)
122
+ {
123
+ Validate::isDate($lastModified);
124
+ return new AccessCondition(
125
+ Resources::IF_MODIFIED_SINCE,
126
+ $lastModified
127
+ );
128
+ }
129
+
130
+ /**
131
+ * Returns an access condition such that an operation will be performed only if
132
+ * the resource's ETag value does not match the specified ETag value.
133
+ * <p>
134
+ * Setting this access condition modifies the request to include the HTTP
135
+ * <i>If-None-Match</i> conditional header. If this access condition is set, the
136
+ * operation is performed only if the ETag of the resource does not match the
137
+ * specified ETag.
138
+ * <p>
139
+ * For more information,
140
+ * see <a href= 'http://go.microsoft.com/fwlink/?LinkID=224642&clcid=0x409'>
141
+ * Specifying Conditional Headers for Blob Service Operations</a>.
142
+ *
143
+ * @param string $etag string that represents the ETag value to check.
144
+ *
145
+ * @return \MicrosoftAzure\Storage\Blob\Models\AccessCondition
146
+ */
147
+ public static function ifNoneMatch($etag)
148
+ {
149
+ return new AccessCondition(Resources::IF_NONE_MATCH, $etag);
150
+ }
151
+
152
+ /**
153
+ * Returns an access condition such that an operation will be performed only if
154
+ * the resource has not been modified since the specified time.
155
+ * <p>
156
+ * Setting this access condition modifies the request to include the HTTP
157
+ * <i>If-Unmodified-Since</i> conditional header. If this access condition is
158
+ * set, the operation is performed only if the resource has not been modified
159
+ * since the specified time.
160
+ * <p>
161
+ * For more information, see
162
+ * <a href= 'http://go.microsoft.com/fwlink/?LinkID=224642&clcid=0x409'>
163
+ * Specifying Conditional Headers for Blob Service Operations</a>.
164
+ *
165
+ * @param \DateTime $lastModified date that represents the last-modified
166
+ * time to check for the resource.
167
+ *
168
+ * @return \MicrosoftAzure\Storage\Blob\Models\AccessCondition
169
+ */
170
+ public static function ifNotModifiedSince($lastModified)
171
+ {
172
+ Validate::isDate($lastModified);
173
+ return new AccessCondition(
174
+ Resources::IF_UNMODIFIED_SINCE,
175
+ $lastModified
176
+ );
177
+ }
178
+
179
+ /**
180
+ * Sets header type
181
+ *
182
+ * @param string $headerType can be one of Resources
183
+ *
184
+ * @return none.
185
+ */
186
+ public function setHeader($headerType)
187
+ {
188
+ $valid = AccessCondition::isValid($headerType);
189
+ Validate::isTrue($valid, Resources::INVALID_HT_MSG);
190
+
191
+ $this->_header = $headerType;
192
+ }
193
+
194
+ /**
195
+ * Gets header type
196
+ *
197
+ * @return string.
198
+ */
199
+ public function getHeader()
200
+ {
201
+ return $this->_header;
202
+ }
203
+
204
+ /**
205
+ * Sets the header value
206
+ *
207
+ * @param string $value the value to use
208
+ *
209
+ * @return none
210
+ */
211
+ public function setValue($value)
212
+ {
213
+ $this->_value = $value;
214
+ }
215
+
216
+ /**
217
+ * Gets the header value
218
+ *
219
+ * @return string
220
+ */
221
+ public function getValue()
222
+ {
223
+ return $this->_value;
224
+ }
225
+
226
+ /**
227
+ * Check if the $headerType belongs to valid header types
228
+ *
229
+ * @param string $headerType candidate header type
230
+ *
231
+ * @return boolean
232
+ */
233
+ public static function isValid($headerType)
234
+ {
235
+ if ($headerType == Resources::EMPTY_STRING
236
+ || $headerType == Resources::IF_UNMODIFIED_SINCE
237
+ || $headerType == Resources::IF_MATCH
238
+ || $headerType == Resources::IF_MODIFIED_SINCE
239
+ || $headerType == Resources::IF_NONE_MATCH
240
+ ) {
241
+ return true;
242
+ } else {
243
+ return false;
244
+ }
245
+ }
246
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/AccessPolicy.php ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
28
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
29
+
30
+ /**
31
+ * Holds container access policy elements
32
+ *
33
+ * @category Microsoft
34
+ * @package MicrosoftAzure\Storage\Blob\Models
35
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
36
+ * @copyright 2016 Microsoft Corporation
37
+ * @license https://github.com/azure/azure-storage-php/LICENSE
38
+ * @version Release: 0.11.0
39
+ * @link https://github.com/azure/azure-storage-php
40
+ */
41
+ class AccessPolicy
42
+ {
43
+ /**
44
+ * @var string
45
+ */
46
+ private $_start;
47
+
48
+ /**
49
+ * @var \DateTime
50
+ */
51
+ private $_expiry;
52
+
53
+ /**
54
+ * @var \DateTime
55
+ */
56
+ private $_permission;
57
+
58
+ /**
59
+ * Gets start.
60
+ *
61
+ * @return \DateTime.
62
+ */
63
+ public function getStart()
64
+ {
65
+ return $this->_start;
66
+ }
67
+
68
+ /**
69
+ * Sets start.
70
+ *
71
+ * @param \DateTime $start value.
72
+ *
73
+ * @return none.
74
+ */
75
+ public function setStart($start)
76
+ {
77
+ Validate::isDate($start);
78
+ $this->_start = $start;
79
+ }
80
+
81
+ /**
82
+ * Gets expiry.
83
+ *
84
+ * @return \DateTime.
85
+ */
86
+ public function getExpiry()
87
+ {
88
+ return $this->_expiry;
89
+ }
90
+
91
+ /**
92
+ * Sets expiry.
93
+ *
94
+ * @param \DateTime $expiry value.
95
+ *
96
+ * @return none.
97
+ */
98
+ public function setExpiry($expiry)
99
+ {
100
+ Validate::isDate($expiry);
101
+ $this->_expiry = $expiry;
102
+ }
103
+
104
+ /**
105
+ * Gets permission.
106
+ *
107
+ * @return string.
108
+ */
109
+ public function getPermission()
110
+ {
111
+ return $this->_permission;
112
+ }
113
+
114
+ /**
115
+ * Sets permission.
116
+ *
117
+ * @param string $permission value.
118
+ *
119
+ * @return none.
120
+ */
121
+ public function setPermission($permission)
122
+ {
123
+ $this->_permission = $permission;
124
+ }
125
+
126
+ /**
127
+ * Converts this current object to XML representation.
128
+ *
129
+ * @return array.
130
+ */
131
+ public function toArray()
132
+ {
133
+ $array = array();
134
+
135
+ $array['Start'] = Utilities::convertToEdmDateTime($this->_start);
136
+ $array['Expiry'] = Utilities::convertToEdmDateTime($this->_expiry);
137
+ $array['Permission'] = $this->_permission;
138
+
139
+ return $array;
140
+ }
141
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/AcquireLeaseOptions.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Optional parameters for acquireLease wrapper
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class AcquireLeaseOptions extends BlobServiceOptions
39
+ {
40
+ /**
41
+ * @var AccessCondition
42
+ */
43
+ private $_accessCondition;
44
+
45
+ /**
46
+ * Gets access condition
47
+ *
48
+ * @return AccessCondition
49
+ */
50
+ public function getAccessCondition()
51
+ {
52
+ return $this->_accessCondition;
53
+ }
54
+
55
+ /**
56
+ * Sets access condition
57
+ *
58
+ * @param AccessCondition $accessCondition value to use.
59
+ *
60
+ * @return none.
61
+ */
62
+ public function setAccessCondition($accessCondition)
63
+ {
64
+ $this->_accessCondition = $accessCondition;
65
+ }
66
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/AcquireLeaseResult.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
27
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
28
+
29
+ /**
30
+ * The result of calling acquireLease API.
31
+ *
32
+ * @category Microsoft
33
+ * @package MicrosoftAzure\Storage\Blob\Models
34
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
35
+ * @copyright 2016 Microsoft Corporation
36
+ * @license https://github.com/azure/azure-storage-php/LICENSE
37
+ * @version Release: 0.11.0
38
+ * @link https://github.com/azure/azure-storage-php
39
+ */
40
+ class AcquireLeaseResult
41
+ {
42
+ /**
43
+ * @var string
44
+ */
45
+ private $_leaseId;
46
+
47
+ /**
48
+ * Creates AcquireLeaseResult from response headers
49
+ *
50
+ * @param array $headers response headers
51
+ *
52
+ * @return AcquireLeaseResult
53
+ */
54
+ public static function create($headers)
55
+ {
56
+ $result = new AcquireLeaseResult();
57
+
58
+ $result->setLeaseId(
59
+ Utilities::tryGetValue($headers, Resources::X_MS_LEASE_ID)
60
+ );
61
+
62
+ return $result;
63
+ }
64
+
65
+ /**
66
+ * Gets lease Id for the blob
67
+ *
68
+ * @return string
69
+ */
70
+ public function getLeaseId()
71
+ {
72
+ return $this->_leaseId;
73
+ }
74
+
75
+ /**
76
+ * Sets lease Id for the blob
77
+ *
78
+ * @param string $leaseId the blob lease id.
79
+ *
80
+ * @return none
81
+ */
82
+ public function setLeaseId($leaseId)
83
+ {
84
+ $this->_leaseId = $leaseId;
85
+ }
86
+ }
87
+
88
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/Blob.php ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Represents windows azure blob object
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class Blob
39
+ {
40
+ /**
41
+ * @var string
42
+ */
43
+ private $_name;
44
+
45
+ /**
46
+ * @var string
47
+ */
48
+ private $_url;
49
+
50
+ /**
51
+ * @var string
52
+ */
53
+ private $_snapshot;
54
+
55
+ /**
56
+ * @var array
57
+ */
58
+ private $_metadata;
59
+
60
+ /**
61
+ * @var BlobProperties
62
+ */
63
+ private $_properties;
64
+
65
+ /**
66
+ * Gets blob name.
67
+ *
68
+ * @return string.
69
+ */
70
+ public function getName()
71
+ {
72
+ return $this->_name;
73
+ }
74
+
75
+ /**
76
+ * Sets blob name.
77
+ *
78
+ * @param string $name value.
79
+ *
80
+ * @return none.
81
+ */
82
+ public function setName($name)
83
+ {
84
+ $this->_name = $name;
85
+ }
86
+
87
+ /**
88
+ * Gets blob snapshot.
89
+ *
90
+ * @return string.
91
+ */
92
+ public function getSnapshot()
93
+ {
94
+ return $this->_snapshot;
95
+ }
96
+
97
+ /**
98
+ * Sets blob snapshot.
99
+ *
100
+ * @param string $snapshot value.
101
+ *
102
+ * @return none.
103
+ */
104
+ public function setSnapshot($snapshot)
105
+ {
106
+ $this->_snapshot = $snapshot;
107
+ }
108
+
109
+ /**
110
+ * Gets blob url.
111
+ *
112
+ * @return string.
113
+ */
114
+ public function getUrl()
115
+ {
116
+ return $this->_url;
117
+ }
118
+
119
+ /**
120
+ * Sets blob url.
121
+ *
122
+ * @param string $url value.
123
+ *
124
+ * @return none.
125
+ */
126
+ public function setUrl($url)
127
+ {
128
+ $this->_url = $url;
129
+ }
130
+
131
+ /**
132
+ * Gets blob metadata.
133
+ *
134
+ * @return array.
135
+ */
136
+ public function getMetadata()
137
+ {
138
+ return $this->_metadata;
139
+ }
140
+
141
+ /**
142
+ * Sets blob metadata.
143
+ *
144
+ * @param array $metadata value.
145
+ *
146
+ * @return none.
147
+ */
148
+ public function setMetadata($metadata)
149
+ {
150
+ $this->_metadata = $metadata;
151
+ }
152
+
153
+ /**
154
+ * Gets blob properties.
155
+ *
156
+ * @return BlobProperties.
157
+ */
158
+ public function getProperties()
159
+ {
160
+ return $this->_properties;
161
+ }
162
+
163
+ /**
164
+ * Sets blob properties.
165
+ *
166
+ * @param BlobProperties $properties value.
167
+ *
168
+ * @return none.
169
+ */
170
+ public function setProperties($properties)
171
+ {
172
+ $this->_properties = $properties;
173
+ }
174
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/BlobBlockType.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Holds available blob block types
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class BlobBlockType
39
+ {
40
+ const COMMITTED_TYPE = 'Committed';
41
+ const UNCOMMITTED_TYPE = 'Uncommitted';
42
+ const LATEST_TYPE = 'Latest';
43
+
44
+ /**
45
+ * Validates the provided type.
46
+ *
47
+ * @param string $type The entry type.
48
+ *
49
+ * @return boolean
50
+ */
51
+ public static function isValid($type)
52
+ {
53
+ switch ($type) {
54
+ case self::COMMITTED_TYPE:
55
+ case self::LATEST_TYPE:
56
+ case self::UNCOMMITTED_TYPE:
57
+ return true;
58
+
59
+ default:
60
+ return false;
61
+ }
62
+ }
63
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/BlobPrefix.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Represents BlobPrefix object
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class BlobPrefix
39
+ {
40
+ /**
41
+ * @var string
42
+ */
43
+ private $_name;
44
+
45
+ /**
46
+ * Gets blob name.
47
+ *
48
+ * @return string.
49
+ */
50
+ public function getName()
51
+ {
52
+ return $this->_name;
53
+ }
54
+
55
+ /**
56
+ * Sets blob name.
57
+ *
58
+ * @param string $name value.
59
+ *
60
+ * @return none.
61
+ */
62
+ public function setName($name)
63
+ {
64
+ $this->_name = $name;
65
+ }
66
+ }
67
+
68
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/BlobProperties.php ADDED
@@ -0,0 +1,431 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
27
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
28
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
29
+
30
+ /**
31
+ * Represents blob properties
32
+ *
33
+ * @category Microsoft
34
+ * @package MicrosoftAzure\Storage\Blob\Models
35
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
36
+ * @copyright 2016 Microsoft Corporation
37
+ * @license https://github.com/azure/azure-storage-php/LICENSE
38
+ * @version Release: 0.11.0
39
+ * @link https://github.com/azure/azure-storage-php
40
+ */
41
+ class BlobProperties
42
+ {
43
+ /**
44
+ * @var \DateTime
45
+ */
46
+ private $_lastModified;
47
+
48
+ /**
49
+ * @var string
50
+ */
51
+ private $_etag;
52
+
53
+ /**
54
+ * @var string
55
+ */
56
+ private $_contentType;
57
+
58
+ /**
59
+ * @var integer
60
+ */
61
+ private $_contentLength;
62
+
63
+ /**
64
+ * @var string
65
+ */
66
+ private $_contentEncoding;
67
+
68
+ /**
69
+ * @var string
70
+ */
71
+ private $_contentLanguage;
72
+
73
+ /**
74
+ * @var string
75
+ */
76
+ private $_contentMD5;
77
+
78
+ /**
79
+ * @var string
80
+ */
81
+ private $_contentRange;
82
+
83
+ /**
84
+ * @var string
85
+ */
86
+ private $_cacheControl;
87
+
88
+ /**
89
+ * @var string
90
+ */
91
+ private $_blobType;
92
+
93
+ /**
94
+ * @var string
95
+ */
96
+ private $_leaseStatus;
97
+
98
+ /**
99
+ * @var integer
100
+ */
101
+ private $_sequenceNumber;
102
+
103
+ /**
104
+ * Creates BlobProperties object from $parsed response in array representation
105
+ *
106
+ * @param array $parsed parsed response in array format.
107
+ *
108
+ * @return BlobProperties
109
+ */
110
+ public static function create($parsed)
111
+ {
112
+ $result = new BlobProperties();
113
+ $clean = array_change_key_case($parsed);
114
+
115
+ $date = Utilities::tryGetValue($clean, Resources::LAST_MODIFIED);
116
+ $result->setBlobType(Utilities::tryGetValue($clean, 'blobtype'));
117
+ $result->setContentLength(intval($clean[Resources::CONTENT_LENGTH]));
118
+ $result->setETag(Utilities::tryGetValue($clean, Resources::ETAG));
119
+
120
+ if (!is_null($date)) {
121
+ $date = Utilities::rfc1123ToDateTime($date);
122
+ $result->setLastModified($date);
123
+ }
124
+
125
+ $result->setLeaseStatus(Utilities::tryGetValue($clean, 'leasestatus'));
126
+ $result->setLeaseStatus(
127
+ Utilities::tryGetValue(
128
+ $clean, Resources::X_MS_LEASE_STATUS, $result->getLeaseStatus()
129
+ )
130
+ );
131
+ $result->setSequenceNumber(
132
+ intval(
133
+ Utilities::tryGetValue($clean, Resources::X_MS_BLOB_SEQUENCE_NUMBER)
134
+ )
135
+ );
136
+ $result->setContentRange(
137
+ Utilities::tryGetValue($clean, Resources::CONTENT_RANGE)
138
+ );
139
+ $result->setCacheControl(
140
+ Utilities::tryGetValue($clean, Resources::CACHE_CONTROL)
141
+ );
142
+ $result->setBlobType(
143
+ Utilities::tryGetValue(
144
+ $clean, Resources::X_MS_BLOB_TYPE, $result->getBlobType()
145
+ )
146
+ );
147
+ $result->setContentEncoding(
148
+ Utilities::tryGetValue($clean, Resources::CONTENT_ENCODING)
149
+ );
150
+ $result->setContentLanguage(
151
+ Utilities::tryGetValue($clean, Resources::CONTENT_LANGUAGE)
152
+ );
153
+ $result->setContentMD5(
154
+ Utilities::tryGetValue($clean, Resources::CONTENT_MD5)
155
+ );
156
+ $result->setContentType(
157
+ Utilities::tryGetValue($clean, Resources::CONTENT_TYPE)
158
+ );
159
+
160
+ return $result;
161
+ }
162
+
163
+ /**
164
+ * Gets blob lastModified.
165
+ *
166
+ * @return \DateTime.
167
+ */
168
+ public function getLastModified()
169
+ {
170
+ return $this->_lastModified;
171
+ }
172
+
173
+ /**
174
+ * Sets blob lastModified.
175
+ *
176
+ * @param \DateTime $lastModified value.
177
+ *
178
+ * @return none.
179
+ */
180
+ public function setLastModified($lastModified)
181
+ {
182
+ Validate::isDate($lastModified);
183
+ $this->_lastModified = $lastModified;
184
+ }
185
+
186
+ /**
187
+ * Gets blob etag.
188
+ *
189
+ * @return string.
190
+ */
191
+ public function getETag()
192
+ {
193
+ return $this->_etag;
194
+ }
195
+
196
+ /**
197
+ * Sets blob etag.
198
+ *
199
+ * @param string $etag value.
200
+ *
201
+ * @return none.
202
+ */
203
+ public function setETag($etag)
204
+ {
205
+ $this->_etag = $etag;
206
+ }
207
+
208
+ /**
209
+ * Gets blob contentType.
210
+ *
211
+ * @return string.
212
+ */
213
+ public function getContentType()
214
+ {
215
+ return $this->_contentType;
216
+ }
217
+
218
+ /**
219
+ * Sets blob contentType.
220
+ *
221
+ * @param string $contentType value.
222
+ *
223
+ * @return none.
224
+ */
225
+ public function setContentType($contentType)
226
+ {
227
+ $this->_contentType = $contentType;
228
+ }
229
+
230
+ /**
231
+ * Gets blob contentRange.
232
+ *
233
+ * @return string.
234
+ */
235
+ public function getContentRange()
236
+ {
237
+ return $this->_contentRange;
238
+ }
239
+
240
+ /**
241
+ * Sets blob contentRange.
242
+ *
243
+ * @param string $contentRange value.
244
+ *
245
+ * @return none.
246
+ */
247
+ public function setContentRange($contentRange)
248
+ {
249
+ $this->_contentRange = $contentRange;
250
+ }
251
+
252
+ /**
253
+ * Gets blob contentLength.
254
+ *
255
+ * @return integer.
256
+ */
257
+ public function getContentLength()
258
+ {
259
+ return $this->_contentLength;
260
+ }
261
+
262
+ /**
263
+ * Sets blob contentLength.
264
+ *
265
+ * @param integer $contentLength value.
266
+ *
267
+ * @return none.
268
+ */
269
+ public function setContentLength($contentLength)
270
+ {
271
+ Validate::isInteger($contentLength, 'contentLength');
272
+ $this->_contentLength = $contentLength;
273
+ }
274
+
275
+ /**
276
+ * Gets blob contentEncoding.
277
+ *
278
+ * @return string.
279
+ */
280
+ public function getContentEncoding()
281
+ {
282
+ return $this->_contentEncoding;
283
+ }
284
+
285
+ /**
286
+ * Sets blob contentEncoding.
287
+ *
288
+ * @param string $contentEncoding value.
289
+ *
290
+ * @return none.
291
+ */
292
+ public function setContentEncoding($contentEncoding)
293
+ {
294
+ $this->_contentEncoding = $contentEncoding;
295
+ }
296
+
297
+ /**
298
+ * Gets blob contentLanguage.
299
+ *
300
+ * @return string.
301
+ */
302
+ public function getContentLanguage()
303
+ {
304
+ return $this->_contentLanguage;
305
+ }
306
+
307
+ /**
308
+ * Sets blob contentLanguage.
309
+ *
310
+ * @param string $contentLanguage value.
311
+ *
312
+ * @return none.
313
+ */
314
+ public function setContentLanguage($contentLanguage)
315
+ {
316
+ $this->_contentLanguage = $contentLanguage;
317
+ }
318
+
319
+ /**
320
+ * Gets blob contentMD5.
321
+ *
322
+ * @return string.
323
+ */
324
+ public function getContentMD5()
325
+ {
326
+ return $this->_contentMD5;
327
+ }
328
+
329
+ /**
330
+ * Sets blob contentMD5.
331
+ *
332
+ * @param string $contentMD5 value.
333
+ *
334
+ * @return none.
335
+ */
336
+ public function setContentMD5($contentMD5)
337
+ {
338
+ $this->_contentMD5 = $contentMD5;
339
+ }
340
+
341
+ /**
342
+ * Gets blob cacheControl.
343
+ *
344
+ * @return string.
345
+ */
346
+ public function getCacheControl()
347
+ {
348
+ return $this->_cacheControl;
349
+ }
350
+
351
+ /**
352
+ * Sets blob cacheControl.
353
+ *
354
+ * @param string $cacheControl value.
355
+ *
356
+ * @return none.
357
+ */
358
+ public function setCacheControl($cacheControl)
359
+ {
360
+ $this->_cacheControl = $cacheControl;
361
+ }
362
+
363
+ /**
364
+ * Gets blob blobType.
365
+ *
366
+ * @return string.
367
+ */
368
+ public function getBlobType()
369
+ {
370
+ return $this->_blobType;
371
+ }
372
+
373
+ /**
374
+ * Sets blob blobType.
375
+ *
376
+ * @param string $blobType value.
377
+ *
378
+ * @return none.
379
+ */
380
+ public function setBlobType($blobType)
381
+ {
382
+ $this->_blobType = $blobType;
383
+ }
384
+
385
+ /**
386
+ * Gets blob leaseStatus.
387
+ *
388
+ * @return string.
389
+ */
390
+ public function getLeaseStatus()
391
+ {
392
+ return $this->_leaseStatus;
393
+ }
394
+
395
+ /**
396
+ * Sets blob leaseStatus.
397
+ *
398
+ * @param string $leaseStatus value.
399
+ *
400
+ * @return none.
401
+ */
402
+ public function setLeaseStatus($leaseStatus)
403
+ {
404
+ $this->_leaseStatus = $leaseStatus;
405
+ }
406
+
407
+ /**
408
+ * Gets blob sequenceNumber.
409
+ *
410
+ * @return int.
411
+ */
412
+ public function getSequenceNumber()
413
+ {
414
+ return $this->_sequenceNumber;
415
+ }
416
+
417
+ /**
418
+ * Sets blob sequenceNumber.
419
+ *
420
+ * @param int $sequenceNumber value.
421
+ *
422
+ * @return none.
423
+ */
424
+ public function setSequenceNumber($sequenceNumber)
425
+ {
426
+ Validate::isInteger($sequenceNumber, 'sequenceNumber');
427
+ $this->_sequenceNumber = $sequenceNumber;
428
+ }
429
+ }
430
+
431
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/BlobServiceOptions.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Blob service options.
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class BlobServiceOptions
39
+ {
40
+ private $_timeout;
41
+
42
+ /**
43
+ * Gets timeout.
44
+ *
45
+ * @return string.
46
+ */
47
+ public function getTimeout()
48
+ {
49
+ return $this->_timeout;
50
+ }
51
+
52
+ /**
53
+ * Sets timeout.
54
+ *
55
+ * @param string $timeout value.
56
+ *
57
+ * @return none.
58
+ */
59
+ public function setTimeout($timeout)
60
+ {
61
+ $this->_timeout = $timeout;
62
+ }
63
+ }
64
+
65
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/BlobType.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Encapsulates blob types
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class BlobType
39
+ {
40
+ const BLOCK_BLOB = 'BlockBlob';
41
+ const PAGE_BLOB = 'PageBlob';
42
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/Block.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Holds information about blob block.
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class Block
39
+ {
40
+ /**
41
+ * @var string
42
+ */
43
+ private $_blockId;
44
+
45
+ /**
46
+ * @var string
47
+ */
48
+ private $_type;
49
+
50
+ public function __construct($blockId = '', $type = '')
51
+ {
52
+ $this->_blockId = $blockId;
53
+ $this->_type = $type;
54
+ }
55
+
56
+ /**
57
+ * Sets the blockId.
58
+ *
59
+ * @param string $blockId The id of the block.
60
+ *
61
+ * @return none
62
+ */
63
+ public function setBlockId($blockId)
64
+ {
65
+ $this->_blockId = $blockId;
66
+ }
67
+
68
+ /**
69
+ * Gets the blockId.
70
+ *
71
+ * @return string
72
+ */
73
+ public function getBlockId()
74
+ {
75
+ return $this->_blockId;
76
+ }
77
+
78
+ /**
79
+ * Sets the type.
80
+ *
81
+ * @param string $type The type of the block.
82
+ *
83
+ * @return none
84
+ */
85
+ public function setType($type)
86
+ {
87
+ $this->_type = $type;
88
+ }
89
+
90
+ /**
91
+ * Gets the type.
92
+ *
93
+ * @return string
94
+ */
95
+ public function getType()
96
+ {
97
+ return $this->_type;
98
+ }
99
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/BlockList.php ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
27
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
28
+ use MicrosoftAzure\Storage\Common\Internal\Serialization\XmlSerializer;
29
+ use MicrosoftAzure\Storage\Blob\Models\Block;
30
+
31
+ /**
32
+ * Holds block list used for commitBlobBlocks
33
+ *
34
+ * @category Microsoft
35
+ * @package MicrosoftAzure\Storage\Blob\Models
36
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
37
+ * @copyright 2016 Microsoft Corporation
38
+ * @license https://github.com/azure/azure-storage-php/LICENSE
39
+ * @version Release: 0.11.0
40
+ * @link https://github.com/azure/azure-storage-php
41
+ */
42
+ class BlockList
43
+ {
44
+ /**
45
+ * @var array
46
+ */
47
+ private $_entries;
48
+ public static $xmlRootName = 'BlockList';
49
+
50
+ /**
51
+ * Creates block list from array of blocks.
52
+ *
53
+ * @param array $array The blocks array.
54
+ *
55
+ * @return BlockList
56
+ */
57
+ public static function create($array)
58
+ {
59
+ $blockList = new BlockList();
60
+
61
+ foreach ($array as $value) {
62
+ $blockList->addEntry($value->getBlockId(), $value->getType());
63
+ }
64
+
65
+ return $blockList;
66
+ }
67
+
68
+ /**
69
+ * Adds new entry to the block list entries.
70
+ *
71
+ * @param string $blockId The block id.
72
+ * @param string $type The entry type, you can use BlobBlockType.
73
+ *
74
+ * @return none
75
+ */
76
+ public function addEntry($blockId, $type)
77
+ {
78
+ Validate::isString($blockId, 'blockId');
79
+ Validate::isTrue(
80
+ BlobBlockType::isValid($type),
81
+ sprintf(Resources::INVALID_BTE_MSG, get_class(new BlobBlockType()))
82
+ );
83
+ $block = new Block();
84
+ $block->setBlockId($blockId);
85
+ $block->setType($type);
86
+
87
+ $this->_entries[] = $block;
88
+ }
89
+
90
+ /**
91
+ * Addds committed block entry.
92
+ *
93
+ * @param string $blockId The block id.
94
+ *
95
+ * @return none
96
+ */
97
+ public function addCommittedEntry($blockId)
98
+ {
99
+ $this->addEntry($blockId, BlobBlockType::COMMITTED_TYPE);
100
+ }
101
+
102
+ /**
103
+ * Addds uncommitted block entry.
104
+ *
105
+ * @param string $blockId The block id.
106
+ *
107
+ * @return none
108
+ */
109
+ public function addUncommittedEntry($blockId)
110
+ {
111
+ $this->addEntry($blockId, BlobBlockType::UNCOMMITTED_TYPE);
112
+ }
113
+
114
+ /**
115
+ * Addds latest block entry.
116
+ *
117
+ * @param string $blockId The block id.
118
+ *
119
+ * @return none
120
+ */
121
+ public function addLatestEntry($blockId)
122
+ {
123
+ $this->addEntry($blockId, BlobBlockType::LATEST_TYPE);
124
+ }
125
+
126
+ /**
127
+ * Gets blob block entry.
128
+ *
129
+ * @param string $blockId The id of the block.
130
+ *
131
+ * @return Block
132
+ */
133
+ public function getEntry($blockId)
134
+ {
135
+ foreach ($this->_entries as $value) {
136
+ if ($blockId == $value->getBlockId()) {
137
+ return $value;
138
+ }
139
+ }
140
+
141
+ return null;
142
+ }
143
+
144
+ /**
145
+ * Gets all blob block entries.
146
+ *
147
+ * @return string
148
+ */
149
+ public function getEntries()
150
+ {
151
+ return $this->_entries;
152
+ }
153
+
154
+ /**
155
+ * Converts the BlockList object to XML representation
156
+ *
157
+ * @param XmlSerializer $xmlSerializer The XML serializer.
158
+ *
159
+ * @return string
160
+ */
161
+ public function toXml($xmlSerializer)
162
+ {
163
+ $properties = array(XmlSerializer::ROOT_NAME => self::$xmlRootName);
164
+ $array = array();
165
+
166
+ foreach ($this->_entries as $value) {
167
+ $array[] = array(
168
+ $value->getType() => $value->getBlockId()
169
+ );
170
+ }
171
+
172
+ return $xmlSerializer->serialize($array, $properties);
173
+ }
174
+ }
175
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/BreakLeaseResult.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
27
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
28
+
29
+ /**
30
+ * The result of calling breakLease API.
31
+ *
32
+ * @category Microsoft
33
+ * @package MicrosoftAzure\Storage\Blob\Models
34
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
35
+ * @copyright 2016 Microsoft Corporation
36
+ * @license https://github.com/azure/azure-storage-php/LICENSE
37
+ * @version Release: 0.11.0
38
+ * @link https://github.com/azure/azure-storage-php
39
+ */
40
+ class BreakLeaseResult
41
+ {
42
+ /**
43
+ * @var string
44
+ */
45
+ private $_leaseTime;
46
+
47
+ /**
48
+ * Creates BreakLeaseResult from response headers
49
+ *
50
+ * @param array $headers response headers
51
+ *
52
+ * @return BreakLeaseResult
53
+ */
54
+ public static function create($headers)
55
+ {
56
+ $result = new BreakLeaseResult();
57
+
58
+ $result->setLeaseTime(
59
+ Utilities::tryGetValue($headers, Resources::X_MS_LEASE_TIME)
60
+ );
61
+
62
+ return $result;
63
+ }
64
+
65
+ /**
66
+ * Gets lease time.
67
+ *
68
+ * @return string
69
+ */
70
+ public function getLeaseTime()
71
+ {
72
+ return $this->_leaseTime;
73
+ }
74
+
75
+ /**
76
+ * Sets lease time.
77
+ *
78
+ * @param string $leaseTime the blob lease time.
79
+ *
80
+ * @return none
81
+ */
82
+ public function setLeaseTime($leaseTime)
83
+ {
84
+ $this->_leaseTime = $leaseTime;
85
+ }
86
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/CommitBlobBlocksOptions.php ADDED
@@ -0,0 +1,258 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
27
+
28
+ /**
29
+ * Optional parameters for commitBlobBlocks
30
+ *
31
+ * @category Microsoft
32
+ * @package MicrosoftAzure\Storage\Blob\Models
33
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
34
+ * @copyright 2016 Microsoft Corporation
35
+ * @license https://github.com/azure/azure-storage-php/LICENSE
36
+ * @version Release: 0.11.0
37
+ * @link https://github.com/azure/azure-storage-php
38
+ */
39
+ class CommitBlobBlocksOptions extends BlobServiceOptions
40
+ {
41
+ /**
42
+ * @var string
43
+ */
44
+ private $_blobContentType;
45
+
46
+ /**
47
+ * @var string
48
+ */
49
+ private $_blobContentEncoding;
50
+
51
+ /**
52
+ * @var string
53
+ */
54
+ private $_blobContentLanguage;
55
+
56
+ /**
57
+ * @var string
58
+ */
59
+ private $_blobContentMD5;
60
+
61
+ /**
62
+ * @var string
63
+ */
64
+ private $_blobCacheControl;
65
+
66
+ /**
67
+ * @var array
68
+ */
69
+ private $_metadata;
70
+
71
+ /**
72
+ * @var string
73
+ */
74
+ private $_leaseId;
75
+
76
+ /**
77
+ * @var AccessCondition
78
+ */
79
+ private $_accessCondition;
80
+
81
+ /**
82
+ * Gets blob ContentType.
83
+ *
84
+ * @return string.
85
+ */
86
+ public function getBlobContentType()
87
+ {
88
+ return $this->_blobContentType;
89
+ }
90
+
91
+ /**
92
+ * Sets blob ContentType.
93
+ *
94
+ * @param string $blobContentType value.
95
+ *
96
+ * @return none.
97
+ */
98
+ public function setBlobContentType($blobContentType)
99
+ {
100
+ $this->_blobContentType = $blobContentType;
101
+ }
102
+
103
+ /**
104
+ * Gets blob ContentEncoding.
105
+ *
106
+ * @return string.
107
+ */
108
+ public function getBlobContentEncoding()
109
+ {
110
+ return $this->_blobContentEncoding;
111
+ }
112
+
113
+ /**
114
+ * Sets blob ContentEncoding.
115
+ *
116
+ * @param string $blobContentEncoding value.
117
+ *
118
+ * @return none.
119
+ */
120
+ public function setBlobContentEncoding($blobContentEncoding)
121
+ {
122
+ $this->_blobContentEncoding = $blobContentEncoding;
123
+ }
124
+
125
+ /**
126
+ * Gets blob ContentLanguage.
127
+ *
128
+ * @return string.
129
+ */
130
+ public function getBlobContentLanguage()
131
+ {
132
+ return $this->_blobContentLanguage;
133
+ }
134
+
135
+ /**
136
+ * Sets blob ContentLanguage.
137
+ *
138
+ * @param string $blobContentLanguage value.
139
+ *
140
+ * @return none.
141
+ */
142
+ public function setBlobContentLanguage($blobContentLanguage)
143
+ {
144
+ $this->_blobContentLanguage = $blobContentLanguage;
145
+ }
146
+
147
+ /**
148
+ * Gets blob ContentMD5.
149
+ *
150
+ * @return string.
151
+ */
152
+ public function getBlobContentMD5()
153
+ {
154
+ return $this->_blobContentMD5;
155
+ }
156
+
157
+ /**
158
+ * Sets blob ContentMD5.
159
+ *
160
+ * @param string $blobContentMD5 value.
161
+ *
162
+ * @return none.
163
+ */
164
+ public function setBlobContentMD5($blobContentMD5)
165
+ {
166
+ $this->_blobContentMD5 = $blobContentMD5;
167
+ }
168
+
169
+ /**
170
+ * Gets blob cache control.
171
+ *
172
+ * @return string.
173
+ */
174
+ public function getBlobCacheControl()
175
+ {
176
+ return $this->_blobCacheControl;
177
+ }
178
+
179
+ /**
180
+ * Sets blob cacheControl.
181
+ *
182
+ * @param string $blobCacheControl value to use.
183
+ *
184
+ * @return none.
185
+ */
186
+ public function setBlobCacheControl($blobCacheControl)
187
+ {
188
+ $this->_blobCacheControl = $blobCacheControl;
189
+ }
190
+
191
+ /**
192
+ * Gets access condition
193
+ *
194
+ * @return AccessCondition
195
+ */
196
+ public function getAccessCondition()
197
+ {
198
+ return $this->_accessCondition;
199
+ }
200
+
201
+ /**
202
+ * Sets access condition
203
+ *
204
+ * @param AccessCondition $accessCondition value to use.
205
+ *
206
+ * @return none.
207
+ */
208
+ public function setAccessCondition($accessCondition)
209
+ {
210
+ $this->_accessCondition = $accessCondition;
211
+ }
212
+
213
+ /**
214
+ * Gets blob metadata.
215
+ *
216
+ * @return array.
217
+ */
218
+ public function getMetadata()
219
+ {
220
+ return $this->_metadata;
221
+ }
222
+
223
+ /**
224
+ * Sets blob metadata.
225
+ *
226
+ * @param array $metadata value.
227
+ *
228
+ * @return none.
229
+ */
230
+ public function setMetadata($metadata)
231
+ {
232
+ $this->_metadata = $metadata;
233
+ }
234
+
235
+ /**
236
+ * Gets lease Id for the blob
237
+ *
238
+ * @return string
239
+ */
240
+ public function getLeaseId()
241
+ {
242
+ return $this->_leaseId;
243
+ }
244
+
245
+ /**
246
+ * Sets lease Id for the blob
247
+ *
248
+ * @param string $leaseId the blob lease id.
249
+ *
250
+ * @return none
251
+ */
252
+ public function setLeaseId($leaseId)
253
+ {
254
+ $this->_leaseId = $leaseId;
255
+ }
256
+ }
257
+
258
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/Container.php ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
27
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
28
+
29
+ /**
30
+ * WindowsAzure container object.
31
+ *
32
+ * @category Microsoft
33
+ * @package MicrosoftAzure\Storage\Blob\Models
34
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
35
+ * @copyright 2016 Microsoft Corporation
36
+ * @license https://github.com/azure/azure-storage-php/LICENSE
37
+ * @version Release: 0.11.0
38
+ * @link https://github.com/azure/azure-storage-php
39
+ */
40
+ class Container
41
+ {
42
+ /**
43
+ * @var string
44
+ */
45
+ private $_name;
46
+
47
+ /**
48
+ * @var string
49
+ */
50
+ private $_url;
51
+
52
+ /**
53
+ * @var array
54
+ */
55
+ private $_metadata;
56
+
57
+ /**
58
+ * @var ContainerProperties
59
+ */
60
+ private $_properties;
61
+
62
+ /**
63
+ * Gets container name.
64
+ *
65
+ * @return string.
66
+ */
67
+ public function getName()
68
+ {
69
+ return $this->_name;
70
+ }
71
+
72
+ /**
73
+ * Sets container name.
74
+ *
75
+ * @param string $name value.
76
+ *
77
+ * @return none.
78
+ */
79
+ public function setName($name)
80
+ {
81
+ $this->_name = $name;
82
+ }
83
+
84
+ /**
85
+ * Gets container url.
86
+ *
87
+ * @return string.
88
+ */
89
+ public function getUrl()
90
+ {
91
+ return $this->_url;
92
+ }
93
+
94
+ /**
95
+ * Sets container url.
96
+ *
97
+ * @param string $url value.
98
+ *
99
+ * @return none.
100
+ */
101
+ public function setUrl($url)
102
+ {
103
+ $this->_url = $url;
104
+ }
105
+
106
+ /**
107
+ * Gets container metadata.
108
+ *
109
+ * @return array.
110
+ */
111
+ public function getMetadata()
112
+ {
113
+ return $this->_metadata;
114
+ }
115
+
116
+ /**
117
+ * Sets container metadata.
118
+ *
119
+ * @param array $metadata value.
120
+ *
121
+ * @return none.
122
+ */
123
+ public function setMetadata($metadata)
124
+ {
125
+ $this->_metadata = $metadata;
126
+ }
127
+
128
+ /**
129
+ * Gets container properties
130
+ *
131
+ * @return ContainerProperties
132
+ */
133
+ public function getProperties()
134
+ {
135
+ return $this->_properties;
136
+ }
137
+
138
+ /**
139
+ * Sets container properties
140
+ *
141
+ * @param ContainerProperties $properties container properties
142
+ *
143
+ * @return none.
144
+ */
145
+ public function setProperties($properties)
146
+ {
147
+ $this->_properties = $properties;
148
+ }
149
+ }
150
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/ContainerACL.php ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
28
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
29
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
30
+ use MicrosoftAzure\Storage\Blob\Models\AccessPolicy;
31
+ use MicrosoftAzure\Storage\Blob\Models\SignedIdentifier;
32
+ use MicrosoftAzure\Storage\Blob\Models\PublicAccessType;
33
+ use MicrosoftAzure\Storage\Common\Internal\Serialization\XmlSerializer;
34
+
35
+ /**
36
+ * Holds conatiner ACL members.
37
+ *
38
+ * @category Microsoft
39
+ * @package MicrosoftAzure\Storage\Blob\Models
40
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
41
+ * @copyright 2016 Microsoft Corporation
42
+ * @license https://github.com/azure/azure-storage-php/LICENSE
43
+ * @version Release: 0.11.0
44
+ * @link https://github.com/azure/azure-storage-php
45
+ */
46
+ class ContainerAcl
47
+ {
48
+ /**
49
+ * All available types can be found in PublicAccessType
50
+ *
51
+ * @var string
52
+ */
53
+ private $_publicAccess;
54
+
55
+ /**
56
+ * @var array
57
+ */
58
+ private $_signedIdentifiers = array();
59
+
60
+ /*
61
+ * The root name of XML elemenet representation.
62
+ *
63
+ * @var string
64
+ */
65
+ public static $xmlRootName = 'SignedIdentifiers';
66
+
67
+
68
+ /**
69
+ * Parses the given array into signed identifiers.
70
+ *
71
+ * @param string $publicAccess The container public access.
72
+ * @param array $parsed The parsed response into array representation.
73
+ *
74
+ * @return none
75
+ */
76
+ public static function create($publicAccess, $parsed)
77
+ {
78
+ $result = new ContainerAcl();
79
+ $result->_publicAccess = $publicAccess;
80
+ $result->_signedIdentifiers = array();
81
+
82
+ if (!empty($parsed) && is_array($parsed['SignedIdentifier'])) {
83
+ $entries = $parsed['SignedIdentifier'];
84
+ $temp = Utilities::getArray($entries);
85
+
86
+ foreach ($temp as $value) {
87
+ $startString = urldecode($value['AccessPolicy']['Start']);
88
+ $expiryString = urldecode($value['AccessPolicy']['Expiry']);
89
+ $start = Utilities::convertToDateTime($startString);
90
+ $expiry = Utilities::convertToDateTime($expiryString);
91
+ $permission = $value['AccessPolicy']['Permission'];
92
+ $id = $value['Id'];
93
+ $result->addSignedIdentifier($id, $start, $expiry, $permission);
94
+ }
95
+ }
96
+
97
+ return $result;
98
+ }
99
+
100
+ /**
101
+ * Gets container signed modifiers.
102
+ *
103
+ * @return array.
104
+ */
105
+ public function getSignedIdentifiers()
106
+ {
107
+ return $this->_signedIdentifiers;
108
+ }
109
+
110
+ /**
111
+ * Sets container signed modifiers.
112
+ *
113
+ * @param array $signedIdentifiers value.
114
+ *
115
+ * @return none.
116
+ */
117
+ public function setSignedIdentifiers($signedIdentifiers)
118
+ {
119
+ $this->_signedIdentifiers = $signedIdentifiers;
120
+ }
121
+
122
+ /**
123
+ * Gets container publicAccess.
124
+ *
125
+ * @return string.
126
+ */
127
+ public function getPublicAccess()
128
+ {
129
+ return $this->_publicAccess;
130
+ }
131
+
132
+ /**
133
+ * Sets container publicAccess.
134
+ *
135
+ * @param string $publicAccess value.
136
+ *
137
+ * @return none.
138
+ */
139
+ public function setPublicAccess($publicAccess)
140
+ {
141
+ Validate::isTrue(
142
+ PublicAccessType::isValid($publicAccess),
143
+ Resources::INVALID_BLOB_PAT_MSG
144
+ );
145
+ $this->_publicAccess = $publicAccess;
146
+ }
147
+
148
+ /**
149
+ * Adds new signed modifier
150
+ *
151
+ * @param string $id a unique id for this modifier
152
+ * @param \DateTime $start The time at which the Shared Access Signature
153
+ * becomes valid. If omitted, start time for this call is assumed to be
154
+ * the time when the Blob service receives the request.
155
+ * @param \DateTime $expiry The time at which the Shared Access Signature
156
+ * becomes invalid. This field may be omitted if it has been specified as
157
+ * part of a container-level access policy.
158
+ * @param string $permission The permissions associated with the Shared
159
+ * Access Signature. The user is restricted to operations allowed by the
160
+ * permissions. Valid permissions values are read (r), write (w), delete (d) and
161
+ * list (l).
162
+ *
163
+ * @return none.
164
+ *
165
+ * @see http://msdn.microsoft.com/en-us/library/windowsazure/hh508996.aspx
166
+ */
167
+ public function addSignedIdentifier($id, $start, $expiry, $permission)
168
+ {
169
+ Validate::isString($id, 'id');
170
+ Validate::isDate($start);
171
+ Validate::isDate($expiry);
172
+ Validate::isString($permission, 'permission');
173
+
174
+ $accessPolicy = new AccessPolicy();
175
+ $accessPolicy->setStart($start);
176
+ $accessPolicy->setExpiry($expiry);
177
+ $accessPolicy->setPermission($permission);
178
+
179
+ $signedIdentifier = new SignedIdentifier();
180
+ $signedIdentifier->setId($id);
181
+ $signedIdentifier->setAccessPolicy($accessPolicy);
182
+
183
+ $this->_signedIdentifiers[] = $signedIdentifier;
184
+ }
185
+
186
+ /**
187
+ * Converts this object to array representation for XML serialization
188
+ *
189
+ * @return array.
190
+ */
191
+ public function toArray()
192
+ {
193
+ $array = array();
194
+
195
+ foreach ($this->_signedIdentifiers as $value) {
196
+ $array[] = $value->toArray();
197
+ }
198
+
199
+ return $array;
200
+ }
201
+
202
+ /**
203
+ * Converts this current object to XML representation.
204
+ *
205
+ * @param XmlSerializer $xmlSerializer The XML serializer.
206
+ *
207
+ * @return string.
208
+ */
209
+ public function toXml($xmlSerializer)
210
+ {
211
+ $properties = array(
212
+ XmlSerializer::DEFAULT_TAG => 'SignedIdentifier',
213
+ XmlSerializer::ROOT_NAME => self::$xmlRootName
214
+ );
215
+
216
+ return $xmlSerializer->serialize($this->toArray(), $properties);
217
+ }
218
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/ContainerProperties.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Holds container properties fields
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class ContainerProperties
39
+ {
40
+ /**
41
+ * @var \DateTime
42
+ */
43
+ private $_lastModified;
44
+
45
+ /**
46
+ * @var string
47
+ */
48
+ private $_etag;
49
+
50
+ /**
51
+ * Gets container lastModified.
52
+ *
53
+ * @return \DateTime.
54
+ */
55
+ public function getLastModified()
56
+ {
57
+ return $this->_lastModified;
58
+ }
59
+
60
+ /**
61
+ * Sets container lastModified.
62
+ *
63
+ * @param \DateTime $lastModified value.
64
+ *
65
+ * @return none.
66
+ */
67
+ public function setLastModified($lastModified)
68
+ {
69
+ $this->_lastModified = $lastModified;
70
+ }
71
+
72
+ /**
73
+ * Gets container etag.
74
+ *
75
+ * @return string.
76
+ */
77
+ public function getETag()
78
+ {
79
+ return $this->_etag;
80
+ }
81
+
82
+ /**
83
+ * Sets container etag.
84
+ *
85
+ * @param string $etag value.
86
+ *
87
+ * @return none.
88
+ */
89
+ public function setETag($etag)
90
+ {
91
+ $this->_etag = $etag;
92
+ }
93
+ }
94
+
95
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/CopyBlobOptions.php ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
27
+
28
+ /**
29
+ * optional parameters for CopyBlobOptions wrapper
30
+ *
31
+ * @category Microsoft
32
+ * @package MicrosoftAzure\Storage\Blob\Models
33
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
34
+ * @copyright 2016 Microsoft Corporation
35
+ * @license https://github.com/azure/azure-storage-php/LICENSE
36
+ * @version Release: 0.11.0
37
+ * @link https://github.com/azure/azure-storage-php
38
+ */
39
+ class CopyBlobOptions extends BlobServiceOptions
40
+ {
41
+
42
+ /**
43
+ * @var AccessCondition
44
+ */
45
+ private $_accessCondition;
46
+
47
+ /**
48
+ * @var AccessCondition
49
+ */
50
+ private $_sourceAccessCondition;
51
+
52
+ /**
53
+ * @var array
54
+ */
55
+ private $_metadata;
56
+
57
+ /**
58
+ * @var string
59
+ */
60
+ private $_sourceSnapshot;
61
+
62
+ /**
63
+ * @var string
64
+ */
65
+ private $_leaseId;
66
+
67
+ /**
68
+ * @var sourceLeaseId
69
+ */
70
+ private $_sourceLeaseId;
71
+
72
+ /**
73
+ * Gets access condition
74
+ *
75
+ * @return AccessCondition
76
+ */
77
+ public function getAccessCondition()
78
+ {
79
+ return $this->_accessCondition;
80
+ }
81
+
82
+ /**
83
+ * Sets access condition
84
+ *
85
+ * @param AccessCondition $accessCondition value to use.
86
+ *
87
+ * @return none.
88
+ */
89
+ public function setAccessCondition($accessCondition)
90
+ {
91
+ $this->_accessCondition = $accessCondition;
92
+ }
93
+
94
+ /**
95
+ * Gets source access condition
96
+ *
97
+ * @return SourceAccessCondition
98
+ */
99
+ public function getSourceAccessCondition()
100
+ {
101
+ return $this->_sourceAccessCondition;
102
+ }
103
+
104
+ /**
105
+ * Sets source access condition
106
+ *
107
+ * @param SourceAccessCondition $sourceAccessCondition value to use.
108
+ *
109
+ * @return none.
110
+ */
111
+ public function setSourceAccessCondition($sourceAccessCondition)
112
+ {
113
+ $this->_sourceAccessCondition = $sourceAccessCondition;
114
+ }
115
+
116
+ /**
117
+ * Gets metadata.
118
+ *
119
+ * @return array.
120
+ */
121
+ public function getMetadata()
122
+ {
123
+ return $this->_metadata;
124
+ }
125
+
126
+ /**
127
+ * Sets metadata.
128
+ *
129
+ * @param array $metadata value.
130
+ *
131
+ * @return none.
132
+ */
133
+ public function setMetadata($metadata)
134
+ {
135
+ $this->_metadata = $metadata;
136
+ }
137
+
138
+ /**
139
+ * Gets source snapshot.
140
+ *
141
+ * @return string
142
+ */
143
+ public function getSourceSnapshot()
144
+ {
145
+ return $this->_sourceSnapshot;
146
+ }
147
+
148
+ /**
149
+ * Sets source snapshot.
150
+ *
151
+ * @param string $sourceSnapshot value.
152
+ *
153
+ * @return none
154
+ */
155
+ public function setSourceSnapshot($sourceSnapshot)
156
+ {
157
+ $this->_sourceSnapshot = $sourceSnapshot;
158
+ }
159
+
160
+ /**
161
+ * Gets lease ID.
162
+ *
163
+ * @return string
164
+ */
165
+ public function getLeaseId()
166
+ {
167
+ return $this->_leaseId;
168
+ }
169
+
170
+ /**
171
+ * Sets lease ID.
172
+ *
173
+ * @param string $leaseId value.
174
+ *
175
+ * @return none
176
+ */
177
+ public function setLeaseId($leaseId)
178
+ {
179
+ $this->_leaseId = $leaseId;
180
+ }
181
+
182
+ /**
183
+ * Gets source lease ID.
184
+ *
185
+ * @return string
186
+ */
187
+ public function getSourceLeaseId()
188
+ {
189
+ return $this->_sourceLeaseId;
190
+ }
191
+
192
+ /**
193
+ * Sets source lease ID.
194
+ *
195
+ * @param string $sourceLeaseId value.
196
+ *
197
+ * @return none
198
+ */
199
+ public function setSourceLeaseId($sourceLeaseId)
200
+ {
201
+ $this->_sourceLeaseId = $sourceLeaseId;
202
+ }
203
+ }
204
+
205
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/CopyBlobResult.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
28
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
29
+
30
+ /**
31
+ * The result of calling copyBlob API.
32
+ *
33
+ * @category Microsoft
34
+ * @package MicrosoftAzure\Storage\Blob\Models
35
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
36
+ * @copyright 2016 Microsoft Corporation
37
+ * @license https://github.com/azure/azure-storage-php/LICENSE
38
+ * @version Release: 0.11.0
39
+ * @link https://github.com/azure/azure-storage-php
40
+ */
41
+ class CopyBlobResult
42
+ {
43
+ /**
44
+ * @var string
45
+ */
46
+ private $_etag;
47
+
48
+ /**
49
+ * @var \DateTime
50
+ */
51
+ private $_lastModified;
52
+
53
+ /**
54
+ * Creates CopyBlobResult object from the response of the copy blob request.
55
+ *
56
+ * @param array $headers The HTTP response headers in array representation.
57
+ *
58
+ * @return CopyBlobResult
59
+ */
60
+ public static function create($headers)
61
+ {
62
+ $result = new CopyBlobResult();
63
+ $result->setETag(
64
+ Utilities::tryGetValueInsensitive(
65
+ Resources::ETAG,
66
+ $headers
67
+ )
68
+ );
69
+ if (Utilities::arrayKeyExistsInsensitive(Resources::LAST_MODIFIED, $headers)) {
70
+ $lastModified = Utilities::tryGetValueInsensitive(
71
+ Resources::LAST_MODIFIED,
72
+ $headers
73
+ );
74
+ $result->setLastModified(Utilities::rfc1123ToDateTime($lastModified));
75
+ }
76
+
77
+ return $result;
78
+ }
79
+
80
+ /**
81
+ * Gets ETag.
82
+ *
83
+ * @return string
84
+ */
85
+ public function getETag()
86
+ {
87
+ return $this->_etag;
88
+ }
89
+
90
+ /**
91
+ * Sets ETag.
92
+ *
93
+ * @param string $etag value.
94
+ *
95
+ * @return none
96
+ */
97
+ public function setETag($etag)
98
+ {
99
+ $this->_etag = $etag;
100
+ }
101
+
102
+ /**
103
+ * Gets blob lastModified.
104
+ *
105
+ * @return \DateTime
106
+ */
107
+ public function getLastModified()
108
+ {
109
+ return $this->_lastModified;
110
+ }
111
+
112
+ /**
113
+ * Sets blob lastModified.
114
+ *
115
+ * @param \DateTime $lastModified value.
116
+ *
117
+ * @return none
118
+ */
119
+ public function setLastModified($lastModified)
120
+ {
121
+ $this->_lastModified = $lastModified;
122
+ }
123
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/CreateBlobBlockOptions.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ use MicrosoftAzure\Storage\Blob\Models\CreateBlobOptions;
28
+
29
+ /**
30
+ * Optional parameters for createBlobBlock wrapper
31
+ *
32
+ * @category Microsoft
33
+ * @package MicrosoftAzure\Storage\Blob\Models
34
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
35
+ * @copyright 2016 Microsoft Corporation
36
+ * @license https://github.com/azure/azure-storage-php/LICENSE
37
+ * @version Release: 0.11.0
38
+ * @link https://github.com/azure/azure-storage-php
39
+ */
40
+ class CreateBlobBlockOptions extends BlobServiceOptions
41
+ {
42
+ /**
43
+ * @var string
44
+ */
45
+ private $_contentMD5;
46
+
47
+ /**
48
+ * @var string
49
+ */
50
+ private $_leaseId;
51
+
52
+ /**
53
+ * @var int
54
+ */
55
+ private $_numberOfConcurrency;
56
+
57
+ /**
58
+ * Gets lease Id for the blob
59
+ *
60
+ * @return string
61
+ */
62
+ public function getLeaseId()
63
+ {
64
+ return $this->_leaseId;
65
+ }
66
+
67
+ /**
68
+ * Sets lease Id for the blob
69
+ *
70
+ * @param string $leaseId the blob lease id.
71
+ *
72
+ * @return none
73
+ */
74
+ public function setLeaseId($leaseId)
75
+ {
76
+ $this->_leaseId = $leaseId;
77
+ }
78
+
79
+ /**
80
+ * Gets blob contentMD5.
81
+ *
82
+ * @return string.
83
+ */
84
+ public function getContentMD5()
85
+ {
86
+ return $this->_contentMD5;
87
+ }
88
+
89
+ /**
90
+ * Sets blob contentMD5.
91
+ *
92
+ * @param string $contentMD5 value.
93
+ *
94
+ * @return none.
95
+ */
96
+ public function setContentMD5($contentMD5)
97
+ {
98
+ $this->_contentMD5 = $contentMD5;
99
+ }
100
+
101
+ /**
102
+ * Gets number of concurrency for sending a blob.
103
+ *
104
+ * @return int
105
+ */
106
+ public function getNumberOfConcurrency()
107
+ {
108
+ return $this->_numberOfConcurrency;
109
+ }
110
+
111
+ /**
112
+ * Sets number of concurrency for sending a blob.
113
+ *
114
+ * @param int $numberOfConcurrency the number of concurrent requests.
115
+ */
116
+ public function setNumberOfConcurrency($numberOfConcurrency)
117
+ {
118
+ $this->_numberOfConcurrency = $numberOfConcurrency;
119
+ }
120
+
121
+ /**
122
+ * Construct a CreateBlobBlockOptions object from a createBlobOptions.
123
+ *
124
+ * @param CreateBlobOptions $createBlobOptions
125
+ *
126
+ * @return CreateBlobBlockOptions
127
+ */
128
+ public static function create($createBlobOptions)
129
+ {
130
+ $result = new CreateBlobBlockOptions();
131
+ $result->setTimeout($createBlobOptions->getTimeout());
132
+ $result->setContentMD5($createBlobOptions->getContentMD5());
133
+ $result->setLeaseId($createBlobOptions->getLeaseId());
134
+ $result->setNumberOfConcurrency(
135
+ $createBlobOptions->getNumberOfConcurrency()
136
+ );
137
+ return $result;
138
+ }
139
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/CreateBlobOptions.php ADDED
@@ -0,0 +1,520 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
28
+ use MicrosoftAzure\Storage\Blob\Models\CreateBlobBlockOptions;
29
+
30
+ /**
31
+ * optional parameters for createXXXBlob wrapper
32
+ *
33
+ * @category Microsoft
34
+ * @package MicrosoftAzure\Storage\Blob\Models
35
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
36
+ * @copyright 2016 Microsoft Corporation
37
+ * @license https://github.com/azure/azure-storage-php/LICENSE
38
+ * @version Release: 0.11.0
39
+ * @link https://github.com/azure/azure-storage-php
40
+ */
41
+ class CreateBlobOptions extends BlobServiceOptions
42
+ {
43
+ /**
44
+ * @var string
45
+ */
46
+ private $_contentType;
47
+
48
+ /**
49
+ * @var string
50
+ */
51
+ private $_contentEncoding;
52
+
53
+ /**
54
+ * @var string
55
+ */
56
+ private $_contentLanguage;
57
+
58
+ /**
59
+ * @var string
60
+ */
61
+ private $_contentMD5;
62
+
63
+ /**
64
+ * @var string
65
+ */
66
+ private $_cacheControl;
67
+
68
+ /**
69
+ * @var string
70
+ */
71
+ private $_blobContentType;
72
+
73
+ /**
74
+ * @var string
75
+ */
76
+ private $_blobContentEncoding;
77
+
78
+ /**
79
+ * @var string
80
+ */
81
+ private $_blobContentLanguage;
82
+
83
+ /**
84
+ * @var integer
85
+ */
86
+ private $_blobContentLength;
87
+
88
+ /**
89
+ * @var string
90
+ */
91
+ private $_blobContentMD5;
92
+
93
+ /**
94
+ * @var string
95
+ */
96
+ private $_blobCacheControl;
97
+
98
+ /**
99
+ * @var array
100
+ */
101
+ private $_metadata;
102
+
103
+ /**
104
+ * @var string
105
+ */
106
+ private $_leaseId;
107
+
108
+ /**
109
+ * @var integer
110
+ */
111
+ private $_sequenceNumber;
112
+
113
+ /**
114
+ * @var string
115
+ */
116
+ private $_sequenceNumberAction;
117
+
118
+ /**
119
+ * @var AccessCondition
120
+ */
121
+ private $_accessCondition;
122
+
123
+ /**
124
+ * @var int
125
+ */
126
+ private $_numberOfConcurrency;
127
+
128
+ /**
129
+ * Gets blob ContentType.
130
+ *
131
+ * @return string.
132
+ */
133
+ public function getBlobContentType()
134
+ {
135
+ return $this->_blobContentType;
136
+ }
137
+
138
+ /**
139
+ * Sets blob ContentType.
140
+ *
141
+ * @param string $blobContentType value.
142
+ *
143
+ * @return none.
144
+ */
145
+ public function setBlobContentType($blobContentType)
146
+ {
147
+ $this->_blobContentType = $blobContentType;
148
+ }
149
+
150
+ /**
151
+ * Gets blob ContentEncoding.
152
+ *
153
+ * @return string.
154
+ */
155
+ public function getBlobContentEncoding()
156
+ {
157
+ return $this->_blobContentEncoding;
158
+ }
159
+
160
+ /**
161
+ * Sets blob ContentEncoding.
162
+ *
163
+ * @param string $blobContentEncoding value.
164
+ *
165
+ * @return none.
166
+ */
167
+ public function setBlobContentEncoding($blobContentEncoding)
168
+ {
169
+ $this->_blobContentEncoding = $blobContentEncoding;
170
+ }
171
+
172
+ /**
173
+ * Gets blob ContentLanguage.
174
+ *
175
+ * @return string.
176
+ */
177
+ public function getBlobContentLanguage()
178
+ {
179
+ return $this->_blobContentLanguage;
180
+ }
181
+
182
+ /**
183
+ * Sets blob ContentLanguage.
184
+ *
185
+ * @param string $blobContentLanguage value.
186
+ *
187
+ * @return none.
188
+ */
189
+ public function setBlobContentLanguage($blobContentLanguage)
190
+ {
191
+ $this->_blobContentLanguage = $blobContentLanguage;
192
+ }
193
+
194
+ /**
195
+ * Gets blob ContentLength.
196
+ *
197
+ * @return integer.
198
+ */
199
+ public function getBlobContentLength()
200
+ {
201
+ return $this->_blobContentLength;
202
+ }
203
+
204
+ /**
205
+ * Sets blob ContentLength.
206
+ *
207
+ * @param integer $blobContentLength value.
208
+ *
209
+ * @return none.
210
+ */
211
+ public function setBlobContentLength($blobContentLength)
212
+ {
213
+ Validate::isInteger($blobContentLength, 'blobContentLength');
214
+ $this->_blobContentLength = $blobContentLength;
215
+ }
216
+
217
+ /**
218
+ * Gets blob ContentMD5.
219
+ *
220
+ * @return string.
221
+ */
222
+ public function getBlobContentMD5()
223
+ {
224
+ return $this->_blobContentMD5;
225
+ }
226
+
227
+ /**
228
+ * Sets blob ContentMD5.
229
+ *
230
+ * @param string $blobContentMD5 value.
231
+ *
232
+ * @return none.
233
+ */
234
+ public function setBlobContentMD5($blobContentMD5)
235
+ {
236
+ $this->_blobContentMD5 = $blobContentMD5;
237
+ }
238
+
239
+ /**
240
+ * Gets blob cache control.
241
+ *
242
+ * @return string.
243
+ */
244
+ public function getBlobCacheControl()
245
+ {
246
+ return $this->_blobCacheControl;
247
+ }
248
+
249
+ /**
250
+ * Sets blob cacheControl.
251
+ *
252
+ * @param string $blobCacheControl value to use.
253
+ *
254
+ * @return none.
255
+ */
256
+ public function setBlobCacheControl($blobCacheControl)
257
+ {
258
+ $this->_blobCacheControl = $blobCacheControl;
259
+ }
260
+
261
+ /**
262
+ * Gets blob contentType.
263
+ *
264
+ * @return string.
265
+ */
266
+ public function getContentType()
267
+ {
268
+ return $this->_contentType;
269
+ }
270
+
271
+ /**
272
+ * Sets blob contentType.
273
+ *
274
+ * @param string $contentType value.
275
+ *
276
+ * @return none.
277
+ */
278
+ public function setContentType($contentType)
279
+ {
280
+ $this->_contentType = $contentType;
281
+ }
282
+
283
+ /**
284
+ * Gets contentEncoding.
285
+ *
286
+ * @return string.
287
+ */
288
+ public function getContentEncoding()
289
+ {
290
+ return $this->_contentEncoding;
291
+ }
292
+
293
+ /**
294
+ * Sets contentEncoding.
295
+ *
296
+ * @param string $contentEncoding value.
297
+ *
298
+ * @return none.
299
+ */
300
+ public function setContentEncoding($contentEncoding)
301
+ {
302
+ $this->_contentEncoding = $contentEncoding;
303
+ }
304
+
305
+ /**
306
+ * Gets contentLanguage.
307
+ *
308
+ * @return string.
309
+ */
310
+ public function getContentLanguage()
311
+ {
312
+ return $this->_contentLanguage;
313
+ }
314
+
315
+ /**
316
+ * Sets contentLanguage.
317
+ *
318
+ * @param string $contentLanguage value.
319
+ *
320
+ * @return none.
321
+ */
322
+ public function setContentLanguage($contentLanguage)
323
+ {
324
+ $this->_contentLanguage = $contentLanguage;
325
+ }
326
+
327
+ /**
328
+ * Gets contentMD5.
329
+ *
330
+ * @return string.
331
+ */
332
+ public function getContentMD5()
333
+ {
334
+ return $this->_contentMD5;
335
+ }
336
+
337
+ /**
338
+ * Sets contentMD5.
339
+ *
340
+ * @param string $contentMD5 value.
341
+ *
342
+ * @return none.
343
+ */
344
+ public function setContentMD5($contentMD5)
345
+ {
346
+ $this->_contentMD5 = $contentMD5;
347
+ }
348
+
349
+ /**
350
+ * Gets cacheControl.
351
+ *
352
+ * @return string.
353
+ */
354
+ public function getCacheControl()
355
+ {
356
+ return $this->_cacheControl;
357
+ }
358
+
359
+ /**
360
+ * Sets cacheControl.
361
+ *
362
+ * @param string $cacheControl value to use.
363
+ *
364
+ * @return none.
365
+ */
366
+ public function setCacheControl($cacheControl)
367
+ {
368
+ $this->_cacheControl = $cacheControl;
369
+ }
370
+
371
+ /**
372
+ * Gets access condition
373
+ *
374
+ * @return AccessCondition
375
+ */
376
+ public function getAccessCondition()
377
+ {
378
+ return $this->_accessCondition;
379
+ }
380
+
381
+ /**
382
+ * Sets access condition
383
+ *
384
+ * @param AccessCondition $accessCondition value to use.
385
+ *
386
+ * @return none.
387
+ */
388
+ public function setAccessCondition($accessCondition)
389
+ {
390
+ $this->_accessCondition = $accessCondition;
391
+ }
392
+
393
+ /**
394
+ * Gets blob metadata.
395
+ *
396
+ * @return array.
397
+ */
398
+ public function getMetadata()
399
+ {
400
+ return $this->_metadata;
401
+ }
402
+
403
+ /**
404
+ * Sets blob metadata.
405
+ *
406
+ * @param array $metadata value.
407
+ *
408
+ * @return none.
409
+ */
410
+ public function setMetadata($metadata)
411
+ {
412
+ $this->_metadata = $metadata;
413
+ }
414
+
415
+ /**
416
+ * Gets blob sequenceNumber.
417
+ *
418
+ * @return int.
419
+ */
420
+ public function getSequenceNumber()
421
+ {
422
+ return $this->_sequenceNumber;
423
+ }
424
+
425
+ /**
426
+ * Sets blob sequenceNumber.
427
+ *
428
+ * @param int $sequenceNumber value.
429
+ *
430
+ * @return none.
431
+ */
432
+ public function setSequenceNumber($sequenceNumber)
433
+ {
434
+ Validate::isInteger($sequenceNumber, 'sequenceNumber');
435
+ $this->_sequenceNumber = $sequenceNumber;
436
+ }
437
+
438
+ /**
439
+ * Gets blob sequenceNumberAction.
440
+ *
441
+ * @return string.
442
+ */
443
+ public function getSequenceNumberAction()
444
+ {
445
+ return $this->_sequenceNumberAction;
446
+ }
447
+
448
+ /**
449
+ * Sets blob sequenceNumberAction.
450
+ *
451
+ * @param string $sequenceNumberAction value.
452
+ *
453
+ * @return none.
454
+ */
455
+ public function setSequenceNumberAction($sequenceNumberAction)
456
+ {
457
+ $this->_sequenceNumberAction = $sequenceNumberAction;
458
+ }
459
+
460
+ /**
461
+ * Gets lease Id for the blob
462
+ *
463
+ * @return string
464
+ */
465
+ public function getLeaseId()
466
+ {
467
+ return $this->_leaseId;
468
+ }
469
+
470
+ /**
471
+ * Sets lease Id for the blob
472
+ *
473
+ * @param string $leaseId the blob lease id.
474
+ *
475
+ * @return none
476
+ */
477
+ public function setLeaseId($leaseId)
478
+ {
479
+ $this->_leaseId = $leaseId;
480
+ }
481
+
482
+ /**
483
+ * Gets number of concurrency for sending a blob.
484
+ *
485
+ * @return int
486
+ */
487
+ public function getNumberOfConcurrency()
488
+ {
489
+ return $this->_numberOfConcurrency;
490
+ }
491
+
492
+ /**
493
+ * Sets number of concurrency for sending a blob.
494
+ *
495
+ * @param int $numberOfConcurrency the number of concurrent requests.
496
+ */
497
+ public function setNumberOfConcurrency($numberOfConcurrency)
498
+ {
499
+ $this->_numberOfConcurrency = $numberOfConcurrency;
500
+ }
501
+
502
+ /**
503
+ * Construct a CreateBlobOptions object from a createBlockBlobOptions.
504
+ *
505
+ * @param CreateBlobBlockOptions $createBlobBlockOptions
506
+ *
507
+ * @return CreateBlobOptions
508
+ */
509
+ public static function create($createBlobBlockOptions)
510
+ {
511
+ $result = new CreateBlobOptions();
512
+ $result->setTimeout($createBlobBlockOptions->getTimeout());
513
+ $result->setContentMD5($createBlobBlockOptions->getContentMD5());
514
+ $result->setLeaseId($createBlobBlockOptions->getLeaseId());
515
+ $result->setNumberOfConcurrency(
516
+ $createBlobBlockOptions->getNumberOfConcurrency()
517
+ );
518
+ return $result;
519
+ }
520
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/CreateBlobPagesOptions.php ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Optional parameters for create and clear blob pages
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class CreateBlobPagesOptions extends BlobServiceOptions
39
+ {
40
+ /**
41
+ * @var string
42
+ */
43
+ private $_contentMD5;
44
+
45
+ /**
46
+ * @var string
47
+ */
48
+ private $_leaseId;
49
+
50
+ /**
51
+ * @var AccessCondition
52
+ */
53
+ private $_accessCondition;
54
+
55
+ /**
56
+ * Gets access condition
57
+ *
58
+ * @return AccessCondition
59
+ */
60
+ public function getAccessCondition()
61
+ {
62
+ return $this->_accessCondition;
63
+ }
64
+
65
+ /**
66
+ * Sets access condition
67
+ *
68
+ * @param AccessCondition $accessCondition value to use.
69
+ *
70
+ * @return none.
71
+ */
72
+ public function setAccessCondition($accessCondition)
73
+ {
74
+ $this->_accessCondition = $accessCondition;
75
+ }
76
+
77
+ /**
78
+ * Gets lease Id for the blob
79
+ *
80
+ * @return string
81
+ */
82
+ public function getLeaseId()
83
+ {
84
+ return $this->_leaseId;
85
+ }
86
+
87
+ /**
88
+ * Sets lease Id for the blob
89
+ *
90
+ * @param string $leaseId the blob lease id.
91
+ *
92
+ * @return none
93
+ */
94
+ public function setLeaseId($leaseId)
95
+ {
96
+ $this->_leaseId = $leaseId;
97
+ }
98
+
99
+ /**
100
+ * Gets blob contentMD5.
101
+ *
102
+ * @return string.
103
+ */
104
+ public function getContentMD5()
105
+ {
106
+ return $this->_contentMD5;
107
+ }
108
+
109
+ /**
110
+ * Sets blob contentMD5.
111
+ *
112
+ * @param string $contentMD5 value.
113
+ *
114
+ * @return none.
115
+ */
116
+ public function setContentMD5($contentMD5)
117
+ {
118
+ $this->_contentMD5 = $contentMD5;
119
+ }
120
+ }
121
+
122
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/CreateBlobPagesResult.php ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
27
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
28
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
29
+
30
+ /**
31
+ * Holds result of calling create or clear blob pages
32
+ *
33
+ * @category Microsoft
34
+ * @package MicrosoftAzure\Storage\Blob\Models
35
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
36
+ * @copyright 2016 Microsoft Corporation
37
+ * @license https://github.com/azure/azure-storage-php/LICENSE
38
+ * @version Release: 0.11.0
39
+ * @link https://github.com/azure/azure-storage-php
40
+ */
41
+ class CreateBlobPagesResult
42
+ {
43
+ /**
44
+ * @var \DateTime
45
+ */
46
+ private $_lastModified;
47
+
48
+ /**
49
+ * @var string
50
+ */
51
+ private $_etag;
52
+
53
+ /**
54
+ * @var integer
55
+ */
56
+ private $_sequenceNumber;
57
+
58
+ /**
59
+ * @var string
60
+ */
61
+ private $_contentMD5;
62
+
63
+ /**
64
+ * Creates CreateBlobPagesResult object from $parsed response in array
65
+ * representation
66
+ *
67
+ * @param array $headers HTTP response headers
68
+ *
69
+ * @return CreateBlobPagesResult
70
+ */
71
+ public static function create($headers)
72
+ {
73
+ $result = new CreateBlobPagesResult();
74
+ $clean = array_change_key_case($headers);
75
+
76
+ $date = $clean[Resources::LAST_MODIFIED];
77
+ $date = Utilities::rfc1123ToDateTime($date);
78
+ $result->setETag($clean[Resources::ETAG]);
79
+ $result->setLastModified($date);
80
+ $result->setContentMD5(
81
+ Utilities::tryGetValue($clean, Resources::CONTENT_MD5)
82
+ );
83
+ $result->setSequenceNumber(
84
+ intval(
85
+ Utilities::tryGetValue($clean, Resources::X_MS_BLOB_SEQUENCE_NUMBER)
86
+ )
87
+ );
88
+
89
+ return $result;
90
+ }
91
+
92
+ /**
93
+ * Gets blob lastModified.
94
+ *
95
+ * @return \DateTime.
96
+ */
97
+ public function getLastModified()
98
+ {
99
+ return $this->_lastModified;
100
+ }
101
+
102
+ /**
103
+ * Sets blob lastModified.
104
+ *
105
+ * @param \DateTime $lastModified value.
106
+ *
107
+ * @return none.
108
+ */
109
+ public function setLastModified($lastModified)
110
+ {
111
+ Validate::isDate($lastModified);
112
+ $this->_lastModified = $lastModified;
113
+ }
114
+
115
+ /**
116
+ * Gets blob etag.
117
+ *
118
+ * @return string.
119
+ */
120
+ public function getETag()
121
+ {
122
+ return $this->_etag;
123
+ }
124
+
125
+ /**
126
+ * Sets blob etag.
127
+ *
128
+ * @param string $etag value.
129
+ *
130
+ * @return none.
131
+ */
132
+ public function setETag($etag)
133
+ {
134
+ Validate::isString($etag, 'etag');
135
+ $this->_etag = $etag;
136
+ }
137
+
138
+ /**
139
+ * Gets blob contentMD5.
140
+ *
141
+ * @return string.
142
+ */
143
+ public function getContentMD5()
144
+ {
145
+ return $this->_contentMD5;
146
+ }
147
+
148
+ /**
149
+ * Sets blob contentMD5.
150
+ *
151
+ * @param string $contentMD5 value.
152
+ *
153
+ * @return none.
154
+ */
155
+ public function setContentMD5($contentMD5)
156
+ {
157
+ $this->_contentMD5 = $contentMD5;
158
+ }
159
+
160
+ /**
161
+ * Gets blob sequenceNumber.
162
+ *
163
+ * @return int.
164
+ */
165
+ public function getSequenceNumber()
166
+ {
167
+ return $this->_sequenceNumber;
168
+ }
169
+
170
+ /**
171
+ * Sets blob sequenceNumber.
172
+ *
173
+ * @param int $sequenceNumber value.
174
+ *
175
+ * @return none.
176
+ */
177
+ public function setSequenceNumber($sequenceNumber)
178
+ {
179
+ Validate::isInteger($sequenceNumber, 'sequenceNumber');
180
+ $this->_sequenceNumber = $sequenceNumber;
181
+ }
182
+ }
183
+
184
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/CreateBlobSnapshotOptions.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * The optional parameters for createBlobSnapshot wrapper.
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class CreateBlobSnapshotOptions extends BlobServiceOptions
39
+ {
40
+ /**
41
+ * @var array
42
+ */
43
+ private $_metadata;
44
+
45
+ /**
46
+ * @var AccessCondition
47
+ */
48
+ private $_accessCondition;
49
+
50
+ /**
51
+ * @var string
52
+ */
53
+ private $_leaseId;
54
+
55
+ /**
56
+ * Gets metadata.
57
+ *
58
+ * @return array
59
+ */
60
+ public function getMetadata()
61
+ {
62
+ return $this->_metadata;
63
+ }
64
+
65
+ /**
66
+ * Sets metadata.
67
+ *
68
+ * @param array $metadata The metadata array.
69
+ *
70
+ * @return none
71
+ */
72
+ public function setMetadata($metadata)
73
+ {
74
+ $this->_metadata = $metadata;
75
+ }
76
+
77
+ /**
78
+ * Gets access condition.
79
+ *
80
+ * @return AccessCondition
81
+ */
82
+ public function getAccessCondition()
83
+ {
84
+ return $this->_accessCondition;
85
+ }
86
+
87
+ /**
88
+ * Sets access condition.
89
+ *
90
+ * @param AccessCondition $accessCondition The access condition object.
91
+ *
92
+ * @return none
93
+ */
94
+ public function setAccessCondition($accessCondition)
95
+ {
96
+ $this->_accessCondition = $accessCondition;
97
+ }
98
+
99
+ /**
100
+ * Gets lease Id.
101
+ *
102
+ * @return string
103
+ */
104
+ public function getLeaseId()
105
+ {
106
+ return $this->_leaseId;
107
+ }
108
+
109
+ /**
110
+ * Sets lease Id.
111
+ *
112
+ * @param string $leaseId The lease Id.
113
+ *
114
+ * @return none
115
+ */
116
+ public function setLeaseId($leaseId)
117
+ {
118
+ $this->_leaseId = $leaseId;
119
+ }
120
+
121
+ }
122
+
123
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/CreateBlobSnapshotResult.php ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
27
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
28
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
29
+
30
+ /**
31
+ * The result of creating Blob snapshot.
32
+ *
33
+ * @category Microsoft
34
+ * @package MicrosoftAzure\Storage\Blob\Models
35
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
36
+ * @copyright 2016 Microsoft Corporation
37
+ * @license https://github.com/azure/azure-storage-php/LICENSE
38
+ * @version Release: 0.11.0
39
+ * @link https://github.com/azure/azure-storage-php
40
+ */
41
+ class CreateBlobSnapshotResult
42
+ {
43
+ /**
44
+ * A DateTime value which uniquely identifies the snapshot.
45
+ * @var string
46
+ */
47
+ private $_snapshot;
48
+
49
+ /**
50
+ * The ETag for the destination blob.
51
+ * @var string
52
+ */
53
+ private $_etag;
54
+
55
+ /**
56
+ * The date/time that the copy operation to the destination blob completed.
57
+ * @var \DateTime
58
+ */
59
+ private $_lastModified;
60
+
61
+ /**
62
+ * Creates CreateBlobSnapshotResult object from the response of the
63
+ * create Blob snapshot request.
64
+ *
65
+ * @param array $headers The HTTP response headers in array representation.
66
+ *
67
+ * @return CreateBlobSnapshotResult
68
+ */
69
+ public static function create($headers)
70
+ {
71
+ $result = new CreateBlobSnapshotResult();
72
+ $headerWithLowerCaseKey = array_change_key_case($headers);
73
+
74
+ $result->setETag($headerWithLowerCaseKey[Resources::ETAG]);
75
+
76
+ $result->setLastModified(
77
+ Utilities::rfc1123ToDateTime(
78
+ $headerWithLowerCaseKey[Resources::LAST_MODIFIED]
79
+ )
80
+ );
81
+
82
+ $result->setSnapshot($headerWithLowerCaseKey[Resources::X_MS_SNAPSHOT]);
83
+
84
+ return $result;
85
+ }
86
+
87
+ /**
88
+ * Gets snapshot.
89
+ *
90
+ * @return string
91
+ */
92
+ public function getSnapshot()
93
+ {
94
+ return $this->_snapshot;
95
+ }
96
+
97
+ /**
98
+ * Sets snapshot.
99
+ *
100
+ * @param string $snapshot value.
101
+ *
102
+ * @return none
103
+ */
104
+ public function setSnapshot($snapshot)
105
+ {
106
+ $this->_snapshot = $snapshot;
107
+ }
108
+
109
+ /**
110
+ * Gets ETag.
111
+ *
112
+ * @return string
113
+ */
114
+ public function getETag()
115
+ {
116
+ return $this->_etag;
117
+ }
118
+
119
+ /**
120
+ * Sets ETag.
121
+ *
122
+ * @param string $etag value.
123
+ *
124
+ * @return none
125
+ */
126
+ public function setETag($etag)
127
+ {
128
+ $this->_etag = $etag;
129
+ }
130
+
131
+ /**
132
+ * Gets blob lastModified.
133
+ *
134
+ * @return \DateTime
135
+ */
136
+ public function getLastModified()
137
+ {
138
+ return $this->_lastModified;
139
+ }
140
+
141
+ /**
142
+ * Sets blob lastModified.
143
+ *
144
+ * @param \DateTime $lastModified value.
145
+ *
146
+ * @return none
147
+ */
148
+ public function setLastModified($lastModified)
149
+ {
150
+ $this->_lastModified = $lastModified;
151
+ }
152
+ }
153
+
154
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/CreateContainerOptions.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Blob\Models\BlobServiceOptions;
27
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
28
+
29
+ /**
30
+ * Optional parameters for createContainer API
31
+ *
32
+ * @category Microsoft
33
+ * @package MicrosoftAzure\Storage\Blob\Models
34
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
35
+ * @copyright 2016 Microsoft Corporation
36
+ * @license https://github.com/azure/azure-storage-php/LICENSE
37
+ * @version Release: 0.11.0
38
+ * @link https://github.com/azure/azure-storage-php
39
+ */
40
+ class CreateContainerOptions extends BlobServiceOptions
41
+ {
42
+ /**
43
+ * @var string
44
+ */
45
+ private $_publicAccess;
46
+
47
+ /**
48
+ * @var array
49
+ */
50
+ private $_metadata;
51
+
52
+ /**
53
+ * Gets container public access.
54
+ *
55
+ * @return string.
56
+ */
57
+ public function getPublicAccess()
58
+ {
59
+ return $this->_publicAccess;
60
+ }
61
+
62
+ /**
63
+ * Specifies whether data in the container may be accessed publicly and the level
64
+ * of access. Possible values include:
65
+ * 1) container: Specifies full public read access for container and blob data.
66
+ * Clients can enumerate blobs within the container via anonymous request, but
67
+ * cannot enumerate containers within the storage account.
68
+ * 2) blob: Specifies public read access for blobs. Blob data within this
69
+ * container can be read via anonymous request, but container data is not
70
+ * available. Clients cannot enumerate blobs within the container via
71
+ * anonymous request.
72
+ * If this value is not specified in the request, container data is private to
73
+ * the account owner.
74
+ *
75
+ * @param string $publicAccess access modifier for the container
76
+ *
77
+ * @return none.
78
+ */
79
+ public function setPublicAccess($publicAccess)
80
+ {
81
+ Validate::isString($publicAccess, 'publicAccess');
82
+ $this->_publicAccess = $publicAccess;
83
+ }
84
+
85
+ /**
86
+ * Gets user defined metadata.
87
+ *
88
+ * @return array.
89
+ */
90
+ public function getMetadata()
91
+ {
92
+ return $this->_metadata;
93
+ }
94
+
95
+ /**
96
+ * Sets user defined metadata. This metadata should be added without the header
97
+ * prefix (x-ms-meta-*).
98
+ *
99
+ * @param array $metadata user defined metadata object in array form.
100
+ *
101
+ * @return none.
102
+ */
103
+ public function setMetadata($metadata)
104
+ {
105
+ $this->_metadata = $metadata;
106
+ }
107
+
108
+ /**
109
+ * Adds new metadata element. This element should be added without the header
110
+ * prefix (x-ms-meta-*).
111
+ *
112
+ * @param string $key metadata key element.
113
+ * @param string $value metadata value element.
114
+ *
115
+ * @return none.
116
+ */
117
+ public function addMetadata($key, $value)
118
+ {
119
+ $this->_metadata[$key] = $value;
120
+ }
121
+ }
122
+
123
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/DeleteBlobOptions.php ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
27
+
28
+ /**
29
+ * Optional parameters for deleteBlob wrapper
30
+ *
31
+ * @category Microsoft
32
+ * @package MicrosoftAzure\Storage\Blob\Models
33
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
34
+ * @copyright 2016 Microsoft Corporation
35
+ * @license https://github.com/azure/azure-storage-php/LICENSE
36
+ * @version Release: 0.11.0
37
+ * @link https://github.com/azure/azure-storage-php
38
+ */
39
+ class DeleteBlobOptions extends BlobServiceOptions
40
+ {
41
+ /**
42
+ * @var string
43
+ */
44
+ private $_leaseId;
45
+
46
+ /**
47
+ * @var string
48
+ */
49
+ private $_snapshot;
50
+
51
+ /**
52
+ * @var AccessCondition
53
+ */
54
+ private $_accessCondition;
55
+
56
+ /**
57
+ * @var boolean
58
+ */
59
+ private $_deleteSnaphotsOnly;
60
+
61
+ /**
62
+ * Gets lease Id for the blob
63
+ *
64
+ * @return string
65
+ */
66
+ public function getLeaseId()
67
+ {
68
+ return $this->_leaseId;
69
+ }
70
+
71
+ /**
72
+ * Sets lease Id for the blob
73
+ *
74
+ * @param string $leaseId the blob lease id.
75
+ *
76
+ * @return none
77
+ */
78
+ public function setLeaseId($leaseId)
79
+ {
80
+ $this->_leaseId = $leaseId;
81
+ }
82
+
83
+ /**
84
+ * Gets access condition
85
+ *
86
+ * @return AccessCondition
87
+ */
88
+ public function getAccessCondition()
89
+ {
90
+ return $this->_accessCondition;
91
+ }
92
+
93
+ /**
94
+ * Sets access condition
95
+ *
96
+ * @param AccessCondition $accessCondition value to use.
97
+ *
98
+ * @return none.
99
+ */
100
+ public function setAccessCondition($accessCondition)
101
+ {
102
+ $this->_accessCondition = $accessCondition;
103
+ }
104
+
105
+ /**
106
+ * Gets blob snapshot.
107
+ *
108
+ * @return string.
109
+ */
110
+ public function getSnapshot()
111
+ {
112
+ return $this->_snapshot;
113
+ }
114
+
115
+ /**
116
+ * Sets blob snapshot.
117
+ *
118
+ * @param string $snapshot value.
119
+ *
120
+ * @return none.
121
+ */
122
+ public function setSnapshot($snapshot)
123
+ {
124
+ $this->_snapshot = $snapshot;
125
+ }
126
+
127
+ /**
128
+ * Gets blob deleteSnaphotsOnly.
129
+ *
130
+ * @return boolean.
131
+ */
132
+ public function getDeleteSnaphotsOnly()
133
+ {
134
+ return $this->_deleteSnaphotsOnly;
135
+ }
136
+
137
+ /**
138
+ * Sets blob deleteSnaphotsOnly.
139
+ *
140
+ * @param string $deleteSnaphotsOnly value.
141
+ *
142
+ * @return boolean.
143
+ */
144
+ public function setDeleteSnaphotsOnly($deleteSnaphotsOnly)
145
+ {
146
+ Validate::isBoolean($deleteSnaphotsOnly);
147
+ $this->_deleteSnaphotsOnly = $deleteSnaphotsOnly;
148
+ }
149
+ }
150
+
151
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/DeleteContainerOptions.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * The optional for deleteContainer API.
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class DeleteContainerOptions extends BlobServiceOptions
39
+ {
40
+ /**
41
+ * @var AccessCondition
42
+ */
43
+ private $_accessCondition;
44
+
45
+ /**
46
+ * Gets access condition
47
+ *
48
+ * @return AccessCondition
49
+ */
50
+ public function getAccessCondition()
51
+ {
52
+ return $this->_accessCondition;
53
+ }
54
+
55
+ /**
56
+ * Sets access condition
57
+ *
58
+ * @param AccessCondition $accessCondition value to use.
59
+ *
60
+ * @return none.
61
+ */
62
+ public function setAccessCondition($accessCondition)
63
+ {
64
+ $this->_accessCondition = $accessCondition;
65
+ }
66
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/GetBlobMetadataOptions.php ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Optional parameters for getBlobMetadata wrapper
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class GetBlobMetadataOptions extends BlobServiceOptions
39
+ {
40
+ /**
41
+ * @var string
42
+ */
43
+ private $_leaseId;
44
+
45
+ /**
46
+ * @var string
47
+ */
48
+ private $_snapshot;
49
+
50
+ /**
51
+ * @var AccessCondition
52
+ */
53
+ private $_accessCondition;
54
+
55
+ /**
56
+ * Gets lease Id for the blob
57
+ *
58
+ * @return string
59
+ */
60
+ public function getLeaseId()
61
+ {
62
+ return $this->_leaseId;
63
+ }
64
+
65
+ /**
66
+ * Sets lease Id for the blob
67
+ *
68
+ * @param string $leaseId the blob lease id.
69
+ *
70
+ * @return none
71
+ */
72
+ public function setLeaseId($leaseId)
73
+ {
74
+ $this->_leaseId = $leaseId;
75
+ }
76
+
77
+ /**
78
+ * Gets access condition
79
+ *
80
+ * @return AccessCondition
81
+ */
82
+ public function getAccessCondition()
83
+ {
84
+ return $this->_accessCondition;
85
+ }
86
+
87
+ /**
88
+ * Sets access condition
89
+ *
90
+ * @param AccessCondition $accessCondition value to use.
91
+ *
92
+ * @return none.
93
+ */
94
+ public function setAccessCondition($accessCondition)
95
+ {
96
+ $this->_accessCondition = $accessCondition;
97
+ }
98
+
99
+ /**
100
+ * Gets blob snapshot.
101
+ *
102
+ * @return string.
103
+ */
104
+ public function getSnapshot()
105
+ {
106
+ return $this->_snapshot;
107
+ }
108
+
109
+ /**
110
+ * Sets blob snapshot.
111
+ *
112
+ * @param string $snapshot value.
113
+ *
114
+ * @return none.
115
+ */
116
+ public function setSnapshot($snapshot)
117
+ {
118
+ $this->_snapshot = $snapshot;
119
+ }
120
+ }
121
+
122
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/GetBlobMetadataResult.php ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
27
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
28
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
29
+
30
+ /**
31
+ * Holds results of calling getBlobMetadata wrapper
32
+ *
33
+ * @category Microsoft
34
+ * @package MicrosoftAzure\Storage\Blob\Models
35
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
36
+ * @copyright 2016 Microsoft Corporation
37
+ * @license https://github.com/azure/azure-storage-php/LICENSE
38
+ * @version Release: 0.11.0
39
+ * @link https://github.com/azure/azure-storage-php
40
+ */
41
+ class GetBlobMetadataResult
42
+ {
43
+
44
+ /**
45
+ * @var \DateTime
46
+ */
47
+ private $_lastModified;
48
+
49
+ /**
50
+ * @var string
51
+ */
52
+ private $_etag;
53
+
54
+ /**
55
+ * @var array
56
+ */
57
+ private $_metadata;
58
+
59
+ /**
60
+ * Creates GetBlobMetadataResult from response headers.
61
+ *
62
+ * @param array $headers The HTTP response headers.
63
+ * @param array $metadata The blob metadata array.
64
+ *
65
+ * @return GetBlobMetadataResult
66
+ */
67
+ public static function create($headers, $metadata)
68
+ {
69
+ $result = new GetBlobMetadataResult();
70
+ $date = $headers[Resources::LAST_MODIFIED];
71
+ $result->setLastModified(Utilities::rfc1123ToDateTime($date));
72
+ $result->setETag($headers[Resources::ETAG]);
73
+ $result->setMetadata(is_null($metadata) ? array() : $metadata);
74
+
75
+ return $result;
76
+ }
77
+
78
+ /**
79
+ * Gets blob lastModified.
80
+ *
81
+ * @return \DateTime.
82
+ */
83
+ public function getLastModified()
84
+ {
85
+ return $this->_lastModified;
86
+ }
87
+
88
+ /**
89
+ * Sets blob lastModified.
90
+ *
91
+ * @param \DateTime $lastModified value.
92
+ *
93
+ * @return none.
94
+ */
95
+ public function setLastModified($lastModified)
96
+ {
97
+ Validate::isDate($lastModified);
98
+ $this->_lastModified = $lastModified;
99
+ }
100
+
101
+ /**
102
+ * Gets blob etag.
103
+ *
104
+ * @return string.
105
+ */
106
+ public function getETag()
107
+ {
108
+ return $this->_etag;
109
+ }
110
+
111
+ /**
112
+ * Sets blob etag.
113
+ *
114
+ * @param string $etag value.
115
+ *
116
+ * @return none.
117
+ */
118
+ public function setETag($etag)
119
+ {
120
+ Validate::isString($etag, 'etag');
121
+ $this->_etag = $etag;
122
+ }
123
+
124
+ /**
125
+ * Gets blob metadata.
126
+ *
127
+ * @return array.
128
+ */
129
+ public function getMetadata()
130
+ {
131
+ return $this->_metadata;
132
+ }
133
+
134
+ /**
135
+ * Sets blob metadata.
136
+ *
137
+ * @param array $metadata value.
138
+ *
139
+ * @return none.
140
+ */
141
+ public function setMetadata($metadata)
142
+ {
143
+ $this->_metadata = $metadata;
144
+ }
145
+ }
146
+
147
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/GetBlobOptions.php ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
28
+
29
+ /**
30
+ * Optional parameters for getBlob wrapper
31
+ *
32
+ * @category Microsoft
33
+ * @package MicrosoftAzure\Storage\Blob\Models
34
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
35
+ * @copyright 2016 Microsoft Corporation
36
+ * @license https://github.com/azure/azure-storage-php/LICENSE
37
+ * @version Release: 0.11.0
38
+ * @link https://github.com/azure/azure-storage-php
39
+ */
40
+ class GetBlobOptions extends BlobServiceOptions
41
+ {
42
+ /**
43
+ * @var string
44
+ */
45
+ private $_leaseId;
46
+
47
+ /**
48
+ * @var string
49
+ */
50
+ private $_snapshot;
51
+
52
+ /**
53
+ * @var AccessCondition
54
+ */
55
+ private $_accessCondition;
56
+
57
+ /**
58
+ * @var boolean
59
+ */
60
+ private $_computeRangeMD5;
61
+
62
+ /**
63
+ * @var integer
64
+ */
65
+ private $_rangeStart;
66
+
67
+ /**
68
+ * @var integer
69
+ */
70
+ private $_rangeEnd;
71
+
72
+ /**
73
+ * Gets lease Id for the blob
74
+ *
75
+ * @return string
76
+ */
77
+ public function getLeaseId()
78
+ {
79
+ return $this->_leaseId;
80
+ }
81
+
82
+ /**
83
+ * Sets lease Id for the blob
84
+ *
85
+ * @param string $leaseId the blob lease id.
86
+ *
87
+ * @return none
88
+ */
89
+ public function setLeaseId($leaseId)
90
+ {
91
+ $this->_leaseId = $leaseId;
92
+ }
93
+
94
+ /**
95
+ * Gets access condition
96
+ *
97
+ * @return AccessCondition
98
+ */
99
+ public function getAccessCondition()
100
+ {
101
+ return $this->_accessCondition;
102
+ }
103
+
104
+ /**
105
+ * Sets access condition
106
+ *
107
+ * @param AccessCondition $accessCondition value to use.
108
+ *
109
+ * @return none.
110
+ */
111
+ public function setAccessCondition($accessCondition)
112
+ {
113
+ $this->_accessCondition = $accessCondition;
114
+ }
115
+
116
+ /**
117
+ * Gets blob snapshot.
118
+ *
119
+ * @return string.
120
+ */
121
+ public function getSnapshot()
122
+ {
123
+ return $this->_snapshot;
124
+ }
125
+
126
+ /**
127
+ * Sets blob snapshot.
128
+ *
129
+ * @param string $snapshot value.
130
+ *
131
+ * @return none.
132
+ */
133
+ public function setSnapshot($snapshot)
134
+ {
135
+ $this->_snapshot = $snapshot;
136
+ }
137
+
138
+ /**
139
+ * Gets rangeStart
140
+ *
141
+ * @return integer
142
+ */
143
+ public function getRangeStart()
144
+ {
145
+ return $this->_rangeStart;
146
+ }
147
+
148
+ /**
149
+ * Sets rangeStart
150
+ *
151
+ * @param integer $rangeStart the blob lease id.
152
+ *
153
+ * @return none
154
+ */
155
+ public function setRangeStart($rangeStart)
156
+ {
157
+ Validate::isInteger($rangeStart, 'rangeStart');
158
+ $this->_rangeStart = $rangeStart;
159
+ }
160
+
161
+ /**
162
+ * Gets rangeEnd
163
+ *
164
+ * @return integer
165
+ */
166
+ public function getRangeEnd()
167
+ {
168
+ return $this->_rangeEnd;
169
+ }
170
+
171
+ /**
172
+ * Sets rangeEnd
173
+ *
174
+ * @param integer $rangeEnd range end value in bytes
175
+ *
176
+ * @return none
177
+ */
178
+ public function setRangeEnd($rangeEnd)
179
+ {
180
+ Validate::isInteger($rangeEnd, 'rangeEnd');
181
+ $this->_rangeEnd = $rangeEnd;
182
+ }
183
+
184
+ /**
185
+ * Gets computeRangeMD5
186
+ *
187
+ * @return boolean
188
+ */
189
+ public function getComputeRangeMD5()
190
+ {
191
+ return $this->_computeRangeMD5;
192
+ }
193
+
194
+ /**
195
+ * Sets computeRangeMD5
196
+ *
197
+ * @param boolean $computeRangeMD5 value
198
+ *
199
+ * @return none
200
+ */
201
+ public function setComputeRangeMD5($computeRangeMD5)
202
+ {
203
+ Validate::isBoolean($computeRangeMD5);
204
+ $this->_computeRangeMD5 = $computeRangeMD5;
205
+ }
206
+ }
207
+
208
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/GetBlobPropertiesOptions.php ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Optional parameters for getBlobProperties wrapper
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class GetBlobPropertiesOptions extends BlobServiceOptions
39
+ {
40
+ /**
41
+ * @var string
42
+ */
43
+ private $_leaseId;
44
+
45
+ /**
46
+ * @var string
47
+ */
48
+ private $_snapshot;
49
+
50
+ /**
51
+ * @var AccessCondition
52
+ */
53
+ private $_accessCondition;
54
+
55
+ /**
56
+ * Gets lease Id for the blob
57
+ *
58
+ * @return string
59
+ */
60
+ public function getLeaseId()
61
+ {
62
+ return $this->_leaseId;
63
+ }
64
+
65
+ /**
66
+ * Sets lease Id for the blob
67
+ *
68
+ * @param string $leaseId the blob lease id.
69
+ *
70
+ * @return none
71
+ */
72
+ public function setLeaseId($leaseId)
73
+ {
74
+ $this->_leaseId = $leaseId;
75
+ }
76
+
77
+ /**
78
+ * Gets access condition
79
+ *
80
+ * @return AccessCondition
81
+ */
82
+ public function getAccessCondition()
83
+ {
84
+ return $this->_accessCondition;
85
+ }
86
+
87
+ /**
88
+ * Sets access condition
89
+ *
90
+ * @param AccessCondition $accessCondition value to use.
91
+ *
92
+ * @return none.
93
+ */
94
+ public function setAccessCondition($accessCondition)
95
+ {
96
+ $this->_accessCondition = $accessCondition;
97
+ }
98
+
99
+ /**
100
+ * Gets blob snapshot.
101
+ *
102
+ * @return string.
103
+ */
104
+ public function getSnapshot()
105
+ {
106
+ return $this->_snapshot;
107
+ }
108
+
109
+ /**
110
+ * Sets blob snapshot.
111
+ *
112
+ * @param string $snapshot value.
113
+ *
114
+ * @return none.
115
+ */
116
+ public function setSnapshot($snapshot)
117
+ {
118
+ $this->_snapshot = $snapshot;
119
+ }
120
+ }
121
+
122
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/GetBlobPropertiesResult.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Holds result of calling getBlobProperties
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class GetBlobPropertiesResult
39
+ {
40
+ /**
41
+ * @var BlobProperties
42
+ */
43
+ private $_properties;
44
+
45
+ /**
46
+ * @var array
47
+ */
48
+ private $_metadata;
49
+
50
+ /**
51
+ * Gets blob metadata.
52
+ *
53
+ * @return array.
54
+ */
55
+ public function getMetadata()
56
+ {
57
+ return $this->_metadata;
58
+ }
59
+
60
+ /**
61
+ * Sets blob metadata.
62
+ *
63
+ * @param array $metadata value.
64
+ *
65
+ * @return none.
66
+ */
67
+ public function setMetadata($metadata)
68
+ {
69
+ $this->_metadata = $metadata;
70
+ }
71
+
72
+ /**
73
+ * Gets blob properties.
74
+ *
75
+ * @return BlobProperties.
76
+ */
77
+ public function getProperties()
78
+ {
79
+ return $this->_properties;
80
+ }
81
+
82
+ /**
83
+ * Sets blob properties.
84
+ *
85
+ * @param BlobProperties $properties value.
86
+ *
87
+ * @return none.
88
+ */
89
+ public function setProperties($properties)
90
+ {
91
+ $this->_properties = $properties;
92
+ }
93
+ }
94
+
95
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/GetBlobResult.php ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ use MicrosoftAzure\Storage\Blob\Models\BlobProperties;
28
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
29
+
30
+ /**
31
+ * Holds result of GetBlob API.
32
+ *
33
+ * @category Microsoft
34
+ * @package MicrosoftAzure\Storage\Blob\Models
35
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
36
+ * @copyright 2016 Microsoft Corporation
37
+ * @license https://github.com/azure/azure-storage-php/LICENSE
38
+ * @version Release: 0.11.0
39
+ * @link https://github.com/azure/azure-storage-php
40
+ */
41
+ class GetBlobResult
42
+ {
43
+ /**
44
+ * @var BlobProperties
45
+ */
46
+ private $_properties;
47
+
48
+ /**
49
+ * @var array
50
+ */
51
+ private $_metadata;
52
+
53
+ /**
54
+ * @var StreamInterface
55
+ */
56
+ private $_contentStream;
57
+
58
+ /**
59
+ * Creates GetBlobResult from getBlob call.
60
+ *
61
+ * @param array $headers The HTTP response headers.
62
+ * @param StreamInterface $body The response body.
63
+ * @param array $metadata The blob metadata.
64
+ *
65
+ * @return GetBlobResult
66
+ */
67
+ public static function create($headers, $body, $metadata)
68
+ {
69
+ $result = new GetBlobResult();
70
+ $result->setContentStream($body->detach());
71
+ $result->setProperties(BlobProperties::create($headers));
72
+ $result->setMetadata(is_null($metadata) ? array() : $metadata);
73
+
74
+ return $result;
75
+ }
76
+
77
+ /**
78
+ * Gets blob metadata.
79
+ *
80
+ * @return array
81
+ */
82
+ public function getMetadata()
83
+ {
84
+ return $this->_metadata;
85
+ }
86
+
87
+ /**
88
+ * Sets blob metadata.
89
+ *
90
+ * @param array $metadata value.
91
+ *
92
+ * @return none
93
+ */
94
+ public function setMetadata($metadata)
95
+ {
96
+ $this->_metadata = $metadata;
97
+ }
98
+
99
+ /**
100
+ * Gets blob properties.
101
+ *
102
+ * @return BlobProperties
103
+ */
104
+ public function getProperties()
105
+ {
106
+ return $this->_properties;
107
+ }
108
+
109
+ /**
110
+ * Sets blob properties.
111
+ *
112
+ * @param BlobProperties $properties value.
113
+ *
114
+ * @return none
115
+ */
116
+ public function setProperties($properties)
117
+ {
118
+ $this->_properties = $properties;
119
+ }
120
+
121
+ /**
122
+ * Gets blob contentStream.
123
+ *
124
+ * @return StreamInterface
125
+ */
126
+ public function getContentStream()
127
+ {
128
+ return $this->_contentStream;
129
+ }
130
+
131
+ /**
132
+ * Sets blob contentStream.
133
+ *
134
+ * @param StreamInterface $contentStream The stream handle.
135
+ *
136
+ * @return none
137
+ */
138
+ public function setContentStream($contentStream)
139
+ {
140
+ $this->_contentStream = $contentStream;
141
+ }
142
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/GetContainerACLResult.php ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Blob\Models\ContainerAcl;
27
+
28
+ /**
29
+ * Holds container ACL
30
+ *
31
+ * @category Microsoft
32
+ * @package MicrosoftAzure\Storage\Blob\Models
33
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
34
+ * @copyright 2016 Microsoft Corporation
35
+ * @license https://github.com/azure/azure-storage-php/LICENSE
36
+ * @version Release: 0.11.0
37
+ * @link https://github.com/azure/azure-storage-php
38
+ */
39
+ class GetContainerAclResult
40
+ {
41
+ /**
42
+ * @var ContainerAcl
43
+ */
44
+ private $_containerACL;
45
+
46
+ /**
47
+ * @var \DateTime
48
+ */
49
+ private $_lastModified;
50
+
51
+ /**
52
+ * @var string
53
+ */
54
+ private $_etag;
55
+
56
+ /**
57
+ * Parses the given array into signed identifiers
58
+ *
59
+ * @param string $publicAccess container public access
60
+ * @param string $etag container etag
61
+ * @param \DateTime $lastModified last modification date
62
+ * @param array $parsed parsed response into array
63
+ * representation
64
+ *
65
+ * @return none.
66
+ */
67
+ public static function create($publicAccess, $etag, $lastModified, $parsed)
68
+ {
69
+ $result = new GetContainerAclResult();
70
+ $result->setETag($etag);
71
+ $result->setLastModified($lastModified);
72
+ $acl = ContainerAcl::create($publicAccess, $parsed);
73
+ $result->setContainerAcl($acl);
74
+
75
+ return $result;
76
+ }
77
+
78
+ /**
79
+ * Gets container ACL
80
+ *
81
+ * @return ContainerAcl
82
+ */
83
+ public function getContainerAcl()
84
+ {
85
+ return $this->_containerACL;
86
+ }
87
+
88
+ /**
89
+ * Sets container ACL
90
+ *
91
+ * @param ContainerAcl $containerACL value.
92
+ *
93
+ * @return none.
94
+ */
95
+ public function setContainerAcl($containerACL)
96
+ {
97
+ $this->_containerACL = $containerACL;
98
+ }
99
+
100
+ /**
101
+ * Gets container lastModified.
102
+ *
103
+ * @return \DateTime.
104
+ */
105
+ public function getLastModified()
106
+ {
107
+ return $this->_lastModified;
108
+ }
109
+
110
+ /**
111
+ * Sets container lastModified.
112
+ *
113
+ * @param \DateTime $lastModified value.
114
+ *
115
+ * @return none.
116
+ */
117
+ public function setLastModified($lastModified)
118
+ {
119
+ $this->_lastModified = $lastModified;
120
+ }
121
+
122
+ /**
123
+ * Gets container etag.
124
+ *
125
+ * @return string.
126
+ */
127
+ public function getETag()
128
+ {
129
+ return $this->_etag;
130
+ }
131
+
132
+ /**
133
+ * Sets container etag.
134
+ *
135
+ * @param string $etag value.
136
+ *
137
+ * @return none.
138
+ */
139
+ public function setETag($etag)
140
+ {
141
+ $this->_etag = $etag;
142
+ }
143
+ }
144
+
145
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/GetContainerPropertiesResult.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Holds result of getContainerProperties and getContainerMetadata
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class GetContainerPropertiesResult
39
+ {
40
+ /**
41
+ * @var \DateTime
42
+ */
43
+ private $_lastModified;
44
+
45
+ /**
46
+ * @var string
47
+ */
48
+ private $_etag;
49
+
50
+ /**
51
+ * @var array
52
+ */
53
+ private $_metadata;
54
+
55
+ /**
56
+ * Any operation that modifies the container or its properties or metadata
57
+ * updates the last modified time. Operations on blobs do not affect the last
58
+ * modified time of the container.
59
+ *
60
+ * @return \DateTime.
61
+ */
62
+ public function getLastModified()
63
+ {
64
+ return $this->_lastModified;
65
+ }
66
+
67
+ /**
68
+ * Sets container lastModified.
69
+ *
70
+ * @param \DateTime $lastModified value.
71
+ *
72
+ * @return none.
73
+ */
74
+ public function setLastModified($lastModified)
75
+ {
76
+ $this->_lastModified = $lastModified;
77
+ }
78
+
79
+ /**
80
+ * The entity tag for the container. If the request version is 2011-08-18 or
81
+ * newer, the ETag value will be in quotes.
82
+ *
83
+ * @return string.
84
+ */
85
+ public function getETag()
86
+ {
87
+ return $this->_etag;
88
+ }
89
+
90
+ /**
91
+ * Sets container etag.
92
+ *
93
+ * @param string $etag value.
94
+ *
95
+ * @return none.
96
+ */
97
+ public function setETag($etag)
98
+ {
99
+ $this->_etag = $etag;
100
+ }
101
+
102
+ /**
103
+ * Gets user defined metadata.
104
+ *
105
+ * @return array.
106
+ */
107
+ public function getMetadata()
108
+ {
109
+ return $this->_metadata;
110
+ }
111
+
112
+ /**
113
+ * Sets user defined metadata. This metadata should be added without the header
114
+ * prefix (x-ms-meta-*).
115
+ *
116
+ * @param array $metadata user defined metadata object in array form.
117
+ *
118
+ * @return none.
119
+ */
120
+ public function setMetadata($metadata)
121
+ {
122
+ $this->_metadata = $metadata;
123
+ }
124
+ }
125
+
126
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/LeaseMode.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Modes for leasing a blob
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class LeaseMode
39
+ {
40
+ const ACQUIRE_ACTION = 'acquire';
41
+ const RENEW_ACTION = 'renew';
42
+ const RELEASE_ACTION = 'release';
43
+ const BREAK_ACTION = 'break';
44
+ }
45
+
46
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/ListBlobBlocksOptions.php ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
27
+
28
+ /**
29
+ * Optional parameters for listBlobBlock wrapper
30
+ *
31
+ * @category Microsoft
32
+ * @package MicrosoftAzure\Storage\Blob\Models
33
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
34
+ * @copyright 2016 Microsoft Corporation
35
+ * @license https://github.com/azure/azure-storage-php/LICENSE
36
+ * @version Release: 0.11.0
37
+ * @link https://github.com/azure/azure-storage-php
38
+ */
39
+ class ListBlobBlocksOptions extends BlobServiceOptions
40
+ {
41
+ /**
42
+ * @var string
43
+ */
44
+ private $_leaseId;
45
+
46
+ /**
47
+ * @var string
48
+ */
49
+ private $_snapshot;
50
+
51
+ /**
52
+ * @var boolean
53
+ */
54
+ private $_includeUncommittedBlobs;
55
+
56
+ /**
57
+ * @var boolean
58
+ */
59
+ private $_includeCommittedBlobs;
60
+
61
+ /**
62
+ * Holds result of list type. You can access it by this order:
63
+ * $_listType[$this->_includeUncommittedBlobs][$this->_includeCommittedBlobs]
64
+ *
65
+ * @var array
66
+ */
67
+ private static $_listType;
68
+
69
+ /**
70
+ * Constructs the static variable $listType.
71
+ */
72
+ public function __construct()
73
+ {
74
+ self::$_listType[true][true] = 'all';
75
+ self::$_listType[true][false] = 'uncommitted';
76
+ self::$_listType[false][true] = 'committed';
77
+ self::$_listType[false][false] = 'all';
78
+
79
+ $this->_includeUncommittedBlobs = false;
80
+ $this->_includeCommittedBlobs = false;
81
+ }
82
+
83
+ /**
84
+ * Gets lease Id for the blob
85
+ *
86
+ * @return string
87
+ */
88
+ public function getLeaseId()
89
+ {
90
+ return $this->_leaseId;
91
+ }
92
+
93
+ /**
94
+ * Sets lease Id for the blob
95
+ *
96
+ * @param string $leaseId the blob lease id.
97
+ *
98
+ * @return none
99
+ */
100
+ public function setLeaseId($leaseId)
101
+ {
102
+ $this->_leaseId = $leaseId;
103
+ }
104
+
105
+ /**
106
+ * Gets blob snapshot.
107
+ *
108
+ * @return string.
109
+ */
110
+ public function getSnapshot()
111
+ {
112
+ return $this->_snapshot;
113
+ }
114
+
115
+ /**
116
+ * Sets blob snapshot.
117
+ *
118
+ * @param string $snapshot value.
119
+ *
120
+ * @return none.
121
+ */
122
+ public function setSnapshot($snapshot)
123
+ {
124
+ $this->_snapshot = $snapshot;
125
+ }
126
+
127
+ /**
128
+ * Sets the include uncommittedBlobs flag.
129
+ *
130
+ * @param bool $includeUncommittedBlobs value.
131
+ *
132
+ * @return none.
133
+ */
134
+ public function setIncludeUncommittedBlobs($includeUncommittedBlobs)
135
+ {
136
+ Validate::isBoolean($includeUncommittedBlobs);
137
+ $this->_includeUncommittedBlobs = $includeUncommittedBlobs;
138
+ }
139
+
140
+ /**
141
+ * Indicates if uncommittedBlobs is included or not.
142
+ *
143
+ * @return boolean.
144
+ */
145
+ public function getIncludeUncommittedBlobs()
146
+ {
147
+ return $this->_includeUncommittedBlobs;
148
+ }
149
+
150
+ /**
151
+ * Sets the include committedBlobs flag.
152
+ *
153
+ * @param bool $includeCommittedBlobs value.
154
+ *
155
+ * @return none.
156
+ */
157
+ public function setIncludeCommittedBlobs($includeCommittedBlobs)
158
+ {
159
+ Validate::isBoolean($includeCommittedBlobs);
160
+ $this->_includeCommittedBlobs = $includeCommittedBlobs;
161
+ }
162
+
163
+ /**
164
+ * Indicates if committedBlobs is included or not.
165
+ *
166
+ * @return boolean.
167
+ */
168
+ public function getIncludeCommittedBlobs()
169
+ {
170
+ return $this->_includeCommittedBlobs;
171
+ }
172
+
173
+ /**
174
+ * Gets block list type.
175
+ *
176
+ * @return string
177
+ */
178
+ public function getBlockListType()
179
+ {
180
+ $includeUncommitted = $this->_includeUncommittedBlobs;
181
+ $includeCommitted = $this->_includeCommittedBlobs;
182
+
183
+ return self::$_listType[$includeUncommitted][$includeCommitted];
184
+ }
185
+ }
186
+
187
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/ListBlobBlocksResult.php ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
27
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
28
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
29
+
30
+ /**
31
+ * Holds result of listBlobBlocks
32
+ *
33
+ * @category Microsoft
34
+ * @package MicrosoftAzure\Storage\Blob\Models
35
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
36
+ * @copyright 2016 Microsoft Corporation
37
+ * @license https://github.com/azure/azure-storage-php/LICENSE
38
+ * @version Release: 0.11.0
39
+ * @link https://github.com/azure/azure-storage-php
40
+ */
41
+ class ListBlobBlocksResult
42
+ {
43
+ /**
44
+ * @var \DateTime
45
+ */
46
+ private $_lastModified;
47
+
48
+ /**
49
+ * @var string
50
+ */
51
+ private $_etag;
52
+
53
+ /**
54
+ * @var string
55
+ */
56
+ private $_contentType;
57
+
58
+ /**
59
+ * @var integer
60
+ */
61
+ private $_contentLength;
62
+
63
+ /**
64
+ * @var array
65
+ */
66
+ private $_committedBlocks;
67
+
68
+ /**
69
+ * @var array
70
+ */
71
+ private $_uncommittedBlocks;
72
+
73
+ /**
74
+ * Gets block entries from parsed response
75
+ *
76
+ * @param array $parsed HTTP response
77
+ * @param string $type Block type
78
+ *
79
+ * @return array
80
+ */
81
+ private static function _getEntries($parsed, $type)
82
+ {
83
+ $entries = array();
84
+
85
+ if (is_array($parsed)) {
86
+ $rawEntries = array();
87
+
88
+ if ( array_key_exists($type, $parsed)
89
+ && is_array($parsed[$type])
90
+ && !empty($parsed[$type])
91
+ ) {
92
+ $rawEntries = Utilities::getArray($parsed[$type]['Block']);
93
+ }
94
+
95
+ foreach ($rawEntries as $value) {
96
+ $entries[$value['Name']] = $value['Size'];
97
+ }
98
+ }
99
+
100
+ return $entries;
101
+ }
102
+
103
+ /**
104
+ * Creates ListBlobBlocksResult from given response headers and parsed body
105
+ *
106
+ * @param array $headers HTTP response headers
107
+ * @param array $parsed HTTP response body in array representation
108
+ *
109
+ * @return ListBlobBlocksResult
110
+ */
111
+ public static function create($headers, $parsed)
112
+ {
113
+ $result = new ListBlobBlocksResult();
114
+ $clean = array_change_key_case($headers);
115
+
116
+ $result->setETag(Utilities::tryGetValue($clean, Resources::ETAG));
117
+ $date = Utilities::tryGetValue($clean, Resources::LAST_MODIFIED);
118
+ if (!is_null($date)) {
119
+ $date = Utilities::rfc1123ToDateTime($date);
120
+ $result->setLastModified($date);
121
+ }
122
+ $result->setContentLength(
123
+ intval(
124
+ Utilities::tryGetValue($clean, Resources::X_MS_BLOB_CONTENT_LENGTH)
125
+ )
126
+ );
127
+ $result->setContentType(
128
+ Utilities::tryGetValue($clean, Resources::CONTENT_TYPE)
129
+ );
130
+
131
+ $result->_uncommittedBlocks = self::_getEntries(
132
+ $parsed, 'UncommittedBlocks'
133
+ );
134
+ $result->_committedBlocks = self::_getEntries($parsed, 'CommittedBlocks');
135
+
136
+ return $result;
137
+ }
138
+
139
+ /**
140
+ * Gets blob lastModified.
141
+ *
142
+ * @return \DateTime.
143
+ */
144
+ public function getLastModified()
145
+ {
146
+ return $this->_lastModified;
147
+ }
148
+
149
+ /**
150
+ * Sets blob lastModified.
151
+ *
152
+ * @param \DateTime $lastModified value.
153
+ *
154
+ * @return none.
155
+ */
156
+ public function setLastModified($lastModified)
157
+ {
158
+ Validate::isDate($lastModified);
159
+ $this->_lastModified = $lastModified;
160
+ }
161
+
162
+ /**
163
+ * Gets blob etag.
164
+ *
165
+ * @return string.
166
+ */
167
+ public function getETag()
168
+ {
169
+ return $this->_etag;
170
+ }
171
+
172
+ /**
173
+ * Sets blob etag.
174
+ *
175
+ * @param string $etag value.
176
+ *
177
+ * @return none.
178
+ */
179
+ public function setETag($etag)
180
+ {
181
+ $this->_etag = $etag;
182
+ }
183
+
184
+ /**
185
+ * Gets blob contentType.
186
+ *
187
+ * @return string.
188
+ */
189
+ public function getContentType()
190
+ {
191
+ return $this->_contentType;
192
+ }
193
+
194
+ /**
195
+ * Sets blob contentType.
196
+ *
197
+ * @param string $contentType value.
198
+ *
199
+ * @return none.
200
+ */
201
+ public function setContentType($contentType)
202
+ {
203
+ $this->_contentType = $contentType;
204
+ }
205
+
206
+ /**
207
+ * Gets blob contentLength.
208
+ *
209
+ * @return integer.
210
+ */
211
+ public function getContentLength()
212
+ {
213
+ return $this->_contentLength;
214
+ }
215
+
216
+ /**
217
+ * Sets blob contentLength.
218
+ *
219
+ * @param integer $contentLength value.
220
+ *
221
+ * @return none.
222
+ */
223
+ public function setContentLength($contentLength)
224
+ {
225
+ Validate::isInteger($contentLength, 'contentLength');
226
+ $this->_contentLength = $contentLength;
227
+ }
228
+
229
+ /**
230
+ * Gets uncommitted blocks
231
+ *
232
+ * @return array
233
+ */
234
+ public function getUncommittedBlocks()
235
+ {
236
+ return $this->_uncommittedBlocks;
237
+ }
238
+
239
+ /**
240
+ * Sets uncommitted blocks
241
+ *
242
+ * @param array $uncommittedBlocks The uncommitted blocks entries
243
+ *
244
+ * @return none.
245
+ */
246
+ public function setUncommittedBlocks($uncommittedBlocks)
247
+ {
248
+ $this->_uncommittedBlocks = $uncommittedBlocks;
249
+ }
250
+
251
+ /**
252
+ * Gets committed blocks
253
+ *
254
+ * @return array
255
+ */
256
+ public function getCommittedBlocks()
257
+ {
258
+ return $this->_committedBlocks;
259
+ }
260
+
261
+ /**
262
+ * Sets committed blocks
263
+ *
264
+ * @param array $committedBlocks The committed blocks entries
265
+ *
266
+ * @return none.
267
+ */
268
+ public function setCommittedBlocks($committedBlocks)
269
+ {
270
+ $this->_committedBlocks = $committedBlocks;
271
+ }
272
+ }
273
+
274
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/ListBlobsOptions.php ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
28
+
29
+ /**
30
+ * Optional parameters for listBlobs API.
31
+ *
32
+ * @category Microsoft
33
+ * @package MicrosoftAzure\Storage\Blob\Models
34
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
35
+ * @copyright 2016 Microsoft Corporation
36
+ * @license https://github.com/azure/azure-storage-php/LICENSE
37
+ * @version Release: 0.11.0
38
+ * @link https://github.com/azure/azure-storage-php
39
+ */
40
+ class ListBlobsOptions extends BlobServiceOptions
41
+ {
42
+ /**
43
+ * @var string
44
+ */
45
+ private $_prefix;
46
+
47
+ /**
48
+ * @var string
49
+ */
50
+ private $_marker;
51
+
52
+ /**
53
+ * @var string
54
+ */
55
+ private $_delimiter;
56
+
57
+ /**
58
+ * @var integer
59
+ */
60
+ private $_maxResults;
61
+
62
+ /**
63
+ * @var boolean
64
+ */
65
+ private $_includeMetadata;
66
+
67
+ /**
68
+ * @var boolean
69
+ */
70
+ private $_includeSnapshots;
71
+
72
+ /**
73
+ * @var boolean
74
+ */
75
+ private $_includeUncommittedBlobs;
76
+
77
+ /**
78
+ * Gets prefix.
79
+ *
80
+ * @return string.
81
+ */
82
+ public function getPrefix()
83
+ {
84
+ return $this->_prefix;
85
+ }
86
+
87
+ /**
88
+ * Sets prefix.
89
+ *
90
+ * @param string $prefix value.
91
+ *
92
+ * @return none.
93
+ */
94
+ public function setPrefix($prefix)
95
+ {
96
+ Validate::isString($prefix, 'prefix');
97
+ $this->_prefix = $prefix;
98
+ }
99
+
100
+ /**
101
+ * Gets delimiter.
102
+ *
103
+ * @return string.
104
+ */
105
+ public function getDelimiter()
106
+ {
107
+ return $this->_delimiter;
108
+ }
109
+
110
+ /**
111
+ * Sets prefix.
112
+ *
113
+ * @param string $delimiter value.
114
+ *
115
+ * @return none.
116
+ */
117
+ public function setDelimiter($delimiter)
118
+ {
119
+ Validate::isString($delimiter, 'delimiter');
120
+ $this->_delimiter = $delimiter;
121
+ }
122
+
123
+ /**
124
+ * Gets marker.
125
+ *
126
+ * @return string.
127
+ */
128
+ public function getMarker()
129
+ {
130
+ return $this->_marker;
131
+ }
132
+
133
+ /**
134
+ * Sets marker.
135
+ *
136
+ * @param string $marker value.
137
+ *
138
+ * @return none.
139
+ */
140
+ public function setMarker($marker)
141
+ {
142
+ Validate::isString($marker, 'marker');
143
+ $this->_marker = $marker;
144
+ }
145
+
146
+ /**
147
+ * Gets max results.
148
+ *
149
+ * @return integer.
150
+ */
151
+ public function getMaxResults()
152
+ {
153
+ return $this->_maxResults;
154
+ }
155
+
156
+ /**
157
+ * Sets max results.
158
+ *
159
+ * @param integer $maxResults value.
160
+ *
161
+ * @return none.
162
+ */
163
+ public function setMaxResults($maxResults)
164
+ {
165
+ Validate::isInteger($maxResults, 'maxResults');
166
+ $this->_maxResults = $maxResults;
167
+ }
168
+
169
+ /**
170
+ * Indicates if metadata is included or not.
171
+ *
172
+ * @return boolean.
173
+ */
174
+ public function getIncludeMetadata()
175
+ {
176
+ return $this->_includeMetadata;
177
+ }
178
+
179
+ /**
180
+ * Sets the include metadata flag.
181
+ *
182
+ * @param bool $includeMetadata value.
183
+ *
184
+ * @return none.
185
+ */
186
+ public function setIncludeMetadata($includeMetadata)
187
+ {
188
+ Validate::isBoolean($includeMetadata);
189
+ $this->_includeMetadata = $includeMetadata;
190
+ }
191
+
192
+ /**
193
+ * Indicates if snapshots is included or not.
194
+ *
195
+ * @return boolean.
196
+ */
197
+ public function getIncludeSnapshots()
198
+ {
199
+ return $this->_includeSnapshots;
200
+ }
201
+
202
+ /**
203
+ * Sets the include snapshots flag.
204
+ *
205
+ * @param bool $includeSnapshots value.
206
+ *
207
+ * @return none.
208
+ */
209
+ public function setIncludeSnapshots($includeSnapshots)
210
+ {
211
+ Validate::isBoolean($includeSnapshots);
212
+ $this->_includeSnapshots = $includeSnapshots;
213
+ }
214
+
215
+ /**
216
+ * Indicates if uncommittedBlobs is included or not.
217
+ *
218
+ * @return boolean.
219
+ */
220
+ public function getIncludeUncommittedBlobs()
221
+ {
222
+ return $this->_includeUncommittedBlobs;
223
+ }
224
+
225
+ /**
226
+ * Sets the include uncommittedBlobs flag.
227
+ *
228
+ * @param bool $includeUncommittedBlobs value.
229
+ *
230
+ * @return none.
231
+ */
232
+ public function setIncludeUncommittedBlobs($includeUncommittedBlobs)
233
+ {
234
+ Validate::isBoolean($includeUncommittedBlobs);
235
+ $this->_includeUncommittedBlobs = $includeUncommittedBlobs;
236
+ }
237
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/ListBlobsResult.php ADDED
@@ -0,0 +1,345 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
27
+ use MicrosoftAzure\Storage\Blob\Models\Blob;
28
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
29
+ use MicrosoftAzure\Storage\Common\Internal\InvalidArgumentTypeException;
30
+
31
+ /**
32
+ * Hold result of calliing listBlobs wrapper.
33
+ *
34
+ * @category Microsoft
35
+ * @package MicrosoftAzure\Storage\Blob\Models
36
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
37
+ * @copyright 2016 Microsoft Corporation
38
+ * @license https://github.com/azure/azure-storage-php/LICENSE
39
+ * @version Release: 0.11.0
40
+ * @link https://github.com/azure/azure-storage-php
41
+ */
42
+ class ListBlobsResult
43
+ {
44
+ /**
45
+ * @var array
46
+ */
47
+ private $_blobPrefixes;
48
+
49
+ /**
50
+ * @var Blob[]
51
+ */
52
+ private $_blobs;
53
+
54
+ /**
55
+ * @var string
56
+ */
57
+ private $_delimiter;
58
+
59
+ /**
60
+ * @var string
61
+ */
62
+ private $_prefix;
63
+
64
+ /**
65
+ * @var string
66
+ */
67
+ private $_marker;
68
+
69
+ /**
70
+ * @var string
71
+ */
72
+ private $_nextMarker;
73
+
74
+ /**
75
+ * @var integer
76
+ */
77
+ private $_maxResults;
78
+
79
+ /**
80
+ * @var string
81
+ */
82
+ private $_containerName;
83
+
84
+ /**
85
+ * Creates ListBlobsResult object from parsed XML response.
86
+ *
87
+ * @param array $parsed XML response parsed into array.
88
+ *
89
+ * @return ListBlobsResult
90
+ */
91
+ public static function create($parsed)
92
+ {
93
+ $result = new ListBlobsResult();
94
+ $serviceEndpoint = Utilities::tryGetKeysChainValue(
95
+ $parsed,
96
+ Resources::XTAG_ATTRIBUTES,
97
+ Resources::XTAG_SERVICE_ENDPOINT
98
+ );
99
+ $containerName = Utilities::tryGetKeysChainValue(
100
+ $parsed,
101
+ Resources::XTAG_ATTRIBUTES,
102
+ Resources::XTAG_CONTAINER_NAME
103
+ );
104
+ $result->_containerName = $containerName;
105
+ $result->_prefix = Utilities::tryGetValue(
106
+ $parsed, Resources::QP_PREFIX
107
+ );
108
+ $result->_marker = Utilities::tryGetValue(
109
+ $parsed, Resources::QP_MARKER
110
+ );
111
+ $result->_nextMarker = Utilities::tryGetValue(
112
+ $parsed, Resources::QP_NEXT_MARKER
113
+ );
114
+ $result->_maxResults = intval(
115
+ Utilities::tryGetValue($parsed, Resources::QP_MAX_RESULTS, 0)
116
+ );
117
+ $result->_delimiter = Utilities::tryGetValue(
118
+ $parsed, Resources::QP_DELIMITER
119
+ );
120
+ $result->_blobs = array();
121
+ $result->_blobPrefixes = array();
122
+ $rawBlobs = array();
123
+ $rawBlobPrefixes = array();
124
+
125
+ if ( is_array($parsed['Blobs'])
126
+ && array_key_exists('Blob', $parsed['Blobs'])
127
+ ) {
128
+ $rawBlobs = Utilities::getArray($parsed['Blobs']['Blob']);
129
+ }
130
+
131
+ foreach ($rawBlobs as $value) {
132
+ $blob = new Blob();
133
+ $blob->setName($value['Name']);
134
+ $blob->setUrl($serviceEndpoint . $containerName . '/' . $value['Name']);
135
+ $blob->setSnapshot(Utilities::tryGetValue($value, 'Snapshot'));
136
+ $blob->setProperties(
137
+ BlobProperties::create(
138
+ Utilities::tryGetValue($value, 'Properties')
139
+ )
140
+ );
141
+ $blob->setMetadata(
142
+ Utilities::tryGetValue($value, Resources::QP_METADATA, array())
143
+ );
144
+
145
+ $result->_blobs[] = $blob;
146
+ }
147
+
148
+ if ( is_array($parsed['Blobs'])
149
+ && array_key_exists('BlobPrefix', $parsed['Blobs'])
150
+ ) {
151
+ $rawBlobPrefixes = Utilities::getArray($parsed['Blobs']['BlobPrefix']);
152
+ }
153
+
154
+ foreach ($rawBlobPrefixes as $value) {
155
+ $blobPrefix = new BlobPrefix();
156
+ $blobPrefix->setName($value['Name']);
157
+
158
+ $result->_blobPrefixes[] = $blobPrefix;
159
+ }
160
+
161
+ return $result;
162
+ }
163
+
164
+ /**
165
+ * Gets blobs.
166
+ *
167
+ * @return Blob[]
168
+ */
169
+ public function getBlobs()
170
+ {
171
+ return $this->_blobs;
172
+ }
173
+
174
+ /**
175
+ * Sets blobs.
176
+ *
177
+ * @param Blob[] $blobs list of blobs
178
+ *
179
+ * @return none
180
+ */
181
+ public function setBlobs($blobs)
182
+ {
183
+ $this->_blobs = array();
184
+ foreach ($blobs as $blob) {
185
+ $this->_blobs[] = clone $blob;
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Gets blobPrefixes.
191
+ *
192
+ * @return array
193
+ */
194
+ public function getBlobPrefixes()
195
+ {
196
+ return $this->_blobPrefixes;
197
+ }
198
+
199
+ /**
200
+ * Sets blobPrefixes.
201
+ *
202
+ * @param array $blobPrefixes list of blobPrefixes
203
+ *
204
+ * @return none
205
+ */
206
+ public function setBlobPrefixes($blobPrefixes)
207
+ {
208
+ $this->_blobPrefixes = array();
209
+ foreach ($blobPrefixes as $blob) {
210
+ $this->_blobPrefixes[] = clone $blob;
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Gets prefix.
216
+ *
217
+ * @return string
218
+ */
219
+ public function getPrefix()
220
+ {
221
+ return $this->_prefix;
222
+ }
223
+
224
+ /**
225
+ * Sets prefix.
226
+ *
227
+ * @param string $prefix value.
228
+ *
229
+ * @return none
230
+ */
231
+ public function setPrefix($prefix)
232
+ {
233
+ $this->_prefix = $prefix;
234
+ }
235
+
236
+ /**
237
+ * Gets prefix.
238
+ *
239
+ * @return string
240
+ */
241
+ public function getDelimiter()
242
+ {
243
+ return $this->_delimiter;
244
+ }
245
+
246
+ /**
247
+ * Sets prefix.
248
+ *
249
+ * @param string $delimiter value.
250
+ *
251
+ * @return none
252
+ */
253
+ public function setDelimiter($delimiter)
254
+ {
255
+ $this->_delimiter = $delimiter;
256
+ }
257
+
258
+ /**
259
+ * Gets marker.
260
+ *
261
+ * @return string
262
+ */
263
+ public function getMarker()
264
+ {
265
+ return $this->_marker;
266
+ }
267
+
268
+ /**
269
+ * Sets marker.
270
+ *
271
+ * @param string $marker value.
272
+ *
273
+ * @return none
274
+ */
275
+ public function setMarker($marker)
276
+ {
277
+ $this->_marker = $marker;
278
+ }
279
+
280
+ /**
281
+ * Gets max results.
282
+ *
283
+ * @return integer
284
+ */
285
+ public function getMaxResults()
286
+ {
287
+ return $this->_maxResults;
288
+ }
289
+
290
+ /**
291
+ * Sets max results.
292
+ *
293
+ * @param integer $maxResults value.
294
+ *
295
+ * @return none
296
+ */
297
+ public function setMaxResults($maxResults)
298
+ {
299
+ $this->_maxResults = $maxResults;
300
+ }
301
+
302
+ /**
303
+ * Gets next marker.
304
+ *
305
+ * @return string
306
+ */
307
+ public function getNextMarker()
308
+ {
309
+ return $this->_nextMarker;
310
+ }
311
+
312
+ /**
313
+ * Sets next marker.
314
+ *
315
+ * @param string $nextMarker value.
316
+ *
317
+ * @return none
318
+ */
319
+ public function setNextMarker($nextMarker)
320
+ {
321
+ $this->_nextMarker = $nextMarker;
322
+ }
323
+
324
+ /**
325
+ * Gets container name.
326
+ *
327
+ * @return string
328
+ */
329
+ public function getContainerName()
330
+ {
331
+ return $this->_containerName;
332
+ }
333
+
334
+ /**
335
+ * Sets container name.
336
+ *
337
+ * @param string $containerName value.
338
+ *
339
+ * @return none
340
+ */
341
+ public function setContainerName($containerName)
342
+ {
343
+ $this->_containerName = $containerName;
344
+ }
345
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/ListContainersOptions.php ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ use MicrosoftAzure\Storage\Blob\Models\BlobServiceOptions;
28
+ use \MicrosoftAzure\Storage\Common\Internal\Validate;
29
+
30
+ /**
31
+ * Options for listBlobs API.
32
+ *
33
+ * @category Microsoft
34
+ * @package MicrosoftAzure\Storage\Blob\Models
35
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
36
+ * @copyright 2016 Microsoft Corporation
37
+ * @license https://github.com/azure/azure-storage-php/LICENSE
38
+ * @version Release: 0.11.0
39
+ * @link https://github.com/azure/azure-storage-php
40
+ */
41
+ class ListContainersOptions extends BlobServiceOptions
42
+ {
43
+ /**
44
+ * Filters the results to return only containers whose name begins with the
45
+ * specified prefix.
46
+ *
47
+ * @var string
48
+ */
49
+ private $_prefix;
50
+
51
+ /**
52
+ * Identifies the portion of the list to be returned with the next list operation
53
+ * The operation returns a marker value within the
54
+ * response body if the list returned was not complete. The marker value may
55
+ * then be used in a subsequent call to request the next set of list items.
56
+ * The marker value is opaque to the client.
57
+ *
58
+ * @var string
59
+ */
60
+ private $_marker;
61
+
62
+ /**
63
+ * Specifies the maximum number of containers to return. If the request does not
64
+ * specify maxresults, or specifies a value greater than 5,000, the server will
65
+ * return up to 5,000 items. If the parameter is set to a value less than or
66
+ * equal to zero, the server will return status code 400 (Bad Request).
67
+ *
68
+ * @var string
69
+ */
70
+ private $_maxResults;
71
+
72
+ /**
73
+ * Include this parameter to specify that the container's metadata be returned
74
+ * as part of the response body.
75
+ *
76
+ * @var bool
77
+ */
78
+ private $_includeMetadata;
79
+
80
+ /**
81
+ * Gets prefix.
82
+ *
83
+ * @return string.
84
+ */
85
+ public function getPrefix()
86
+ {
87
+ return $this->_prefix;
88
+ }
89
+
90
+ /**
91
+ * Sets prefix.
92
+ *
93
+ * @param string $prefix value.
94
+ *
95
+ * @return none.
96
+ */
97
+ public function setPrefix($prefix)
98
+ {
99
+ Validate::isString($prefix, 'prefix');
100
+ $this->_prefix = $prefix;
101
+ }
102
+
103
+ /**
104
+ * Gets marker.
105
+ *
106
+ * @return string.
107
+ */
108
+ public function getMarker()
109
+ {
110
+ return $this->_marker;
111
+ }
112
+
113
+ /**
114
+ * Sets marker.
115
+ *
116
+ * @param string $marker value.
117
+ *
118
+ * @return none.
119
+ */
120
+ public function setMarker($marker)
121
+ {
122
+ Validate::isString($marker, 'marker');
123
+ $this->_marker = $marker;
124
+ }
125
+
126
+ /**
127
+ * Gets max results.
128
+ *
129
+ * @return string.
130
+ */
131
+ public function getMaxResults()
132
+ {
133
+ return $this->_maxResults;
134
+ }
135
+
136
+ /**
137
+ * Sets max results.
138
+ *
139
+ * @param string $maxResults value.
140
+ *
141
+ * @return none.
142
+ */
143
+ public function setMaxResults($maxResults)
144
+ {
145
+ Validate::isString($maxResults, 'maxResults');
146
+ $this->_maxResults = $maxResults;
147
+ }
148
+
149
+ /**
150
+ * Indicates if metadata is included or not.
151
+ *
152
+ * @return string.
153
+ */
154
+ public function getIncludeMetadata()
155
+ {
156
+ return $this->_includeMetadata;
157
+ }
158
+
159
+ /**
160
+ * Sets the include metadata flag.
161
+ *
162
+ * @param bool $includeMetadata value.
163
+ *
164
+ * @return none.
165
+ */
166
+ public function setIncludeMetadata($includeMetadata)
167
+ {
168
+ Validate::isBoolean($includeMetadata);
169
+ $this->_includeMetadata = $includeMetadata;
170
+ }
171
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/ListContainersResult.php ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
28
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
29
+ use MicrosoftAzure\Storage\Blob\Models\Container;
30
+ use MicrosoftAzure\Storage\Tests\Unit\Common\Internal\UtilitiesTest;
31
+
32
+ /**
33
+ * Container to hold list container response object.
34
+ *
35
+ * @category Microsoft
36
+ * @package MicrosoftAzure\Storage\Blob\Models
37
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
38
+ * @copyright 2016 Microsoft Corporation
39
+ * @license https://github.com/azure/azure-storage-php/LICENSE
40
+ * @version Release: 0.11.0
41
+ * @link https://github.com/azure/azure-storage-php
42
+ */
43
+ class ListContainersResult
44
+ {
45
+ /**
46
+ * @var array
47
+ */
48
+ private $_containers;
49
+
50
+ /**
51
+ * @var string
52
+ */
53
+ private $_prefix;
54
+
55
+ /**
56
+ * @var string
57
+ */
58
+ private $_marker;
59
+
60
+ /**
61
+ * @var string
62
+ */
63
+ private $_nextMarker;
64
+
65
+ /**
66
+ * @var integer
67
+ */
68
+ private $_maxResults;
69
+
70
+ /**
71
+ * @var string
72
+ */
73
+ private $_accountName;
74
+
75
+ /**
76
+ * Creates ListBlobResult object from parsed XML response.
77
+ *
78
+ * @param array $parsedResponse XML response parsed into array.
79
+ *
80
+ * @return ListBlobResult
81
+ */
82
+ public static function create($parsedResponse)
83
+ {
84
+ $result = new ListContainersResult();
85
+ $serviceEndpoint = Utilities::tryGetKeysChainValue(
86
+ $parsedResponse,
87
+ Resources::XTAG_ATTRIBUTES,
88
+ Resources::XTAG_SERVICE_ENDPOINT
89
+ );
90
+ $result->_accountName = Utilities::tryParseAccountNameFromUrl(
91
+ $serviceEndpoint
92
+ );
93
+ $result->_prefix = Utilities::tryGetValue(
94
+ $parsedResponse, Resources::QP_PREFIX
95
+ );
96
+ $result->_marker = Utilities::tryGetValue(
97
+ $parsedResponse, Resources::QP_MARKER
98
+ );
99
+ $result->_nextMarker = Utilities::tryGetValue(
100
+ $parsedResponse, Resources::QP_NEXT_MARKER
101
+ );
102
+ $result->_maxResults = Utilities::tryGetValue(
103
+ $parsedResponse, Resources::QP_MAX_RESULTS
104
+ );
105
+ $result->_containers = array();
106
+ $rawContainer = array();
107
+
108
+ if ( !empty($parsedResponse['Containers']) ) {
109
+ $containersArray = $parsedResponse['Containers']['Container'];
110
+ $rawContainer = Utilities::getArray($containersArray);
111
+ }
112
+
113
+ foreach ($rawContainer as $value) {
114
+ $container = new Container();
115
+ $container->setName($value['Name']);
116
+ $container->setUrl($serviceEndpoint . $value['Name']);
117
+ $container->setMetadata(
118
+ Utilities::tryGetValue($value, Resources::QP_METADATA, array())
119
+ );
120
+ $properties = new ContainerProperties();
121
+ $date = $value['Properties']['Last-Modified'];
122
+ $date = Utilities::rfc1123ToDateTime($date);
123
+ $properties->setLastModified($date);
124
+ $properties->setETag($value['Properties']['Etag']);
125
+ $container->setProperties($properties);
126
+ $result->_containers[] = $container;
127
+ }
128
+
129
+ return $result;
130
+ }
131
+
132
+ /**
133
+ * Sets containers.
134
+ *
135
+ * @param array $containers list of containers.
136
+ *
137
+ * @return none
138
+ */
139
+ public function setContainers($containers)
140
+ {
141
+ $this->_containers = array();
142
+ foreach ($containers as $container) {
143
+ $this->_containers[] = clone $container;
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Gets containers.
149
+ *
150
+ * @return Container[]
151
+ */
152
+ public function getContainers()
153
+ {
154
+ return $this->_containers;
155
+ }
156
+
157
+ /**
158
+ * Gets prefix.
159
+ *
160
+ * @return string
161
+ */
162
+ public function getPrefix()
163
+ {
164
+ return $this->_prefix;
165
+ }
166
+
167
+ /**
168
+ * Sets prefix.
169
+ *
170
+ * @param string $prefix value.
171
+ *
172
+ * @return none
173
+ */
174
+ public function setPrefix($prefix)
175
+ {
176
+ $this->_prefix = $prefix;
177
+ }
178
+
179
+ /**
180
+ * Gets marker.
181
+ *
182
+ * @return string
183
+ */
184
+ public function getMarker()
185
+ {
186
+ return $this->_marker;
187
+ }
188
+
189
+ /**
190
+ * Sets marker.
191
+ *
192
+ * @param string $marker value.
193
+ *
194
+ * @return none
195
+ */
196
+ public function setMarker($marker)
197
+ {
198
+ $this->_marker = $marker;
199
+ }
200
+
201
+ /**
202
+ * Gets max results.
203
+ *
204
+ * @return string
205
+ */
206
+ public function getMaxResults()
207
+ {
208
+ return $this->_maxResults;
209
+ }
210
+
211
+ /**
212
+ * Sets max results.
213
+ *
214
+ * @param string $maxResults value.
215
+ *
216
+ * @return none
217
+ */
218
+ public function setMaxResults($maxResults)
219
+ {
220
+ $this->_maxResults = $maxResults;
221
+ }
222
+
223
+ /**
224
+ * Gets next marker.
225
+ *
226
+ * @return string
227
+ */
228
+ public function getNextMarker()
229
+ {
230
+ return $this->_nextMarker;
231
+ }
232
+
233
+ /**
234
+ * Sets next marker.
235
+ *
236
+ * @param string $nextMarker value.
237
+ *
238
+ * @return none
239
+ */
240
+ public function setNextMarker($nextMarker)
241
+ {
242
+ $this->_nextMarker = $nextMarker;
243
+ }
244
+
245
+ /**
246
+ * Gets account name.
247
+ *
248
+ * @return string
249
+ */
250
+ public function getAccountName()
251
+ {
252
+ return $this->_accountName;
253
+ }
254
+
255
+ /**
256
+ * Sets account name.
257
+ *
258
+ * @param string $accountName value.
259
+ *
260
+ * @return none
261
+ */
262
+ public function setAccountName($accountName)
263
+ {
264
+ $this->_accountName = $accountName;
265
+ }
266
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/ListPageBlobRangesOptions.php ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
27
+
28
+ /**
29
+ * Optional parameters for listPageBlobRanges wrapper
30
+ *
31
+ * @category Microsoft
32
+ * @package MicrosoftAzure\Storage\Blob\Models
33
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
34
+ * @copyright 2016 Microsoft Corporation
35
+ * @license https://github.com/azure/azure-storage-php/LICENSE
36
+ * @version Release: 0.11.0
37
+ * @link https://github.com/azure/azure-storage-php
38
+ */
39
+ class ListPageBlobRangesOptions extends BlobServiceOptions
40
+ {
41
+ /**
42
+ * @var string
43
+ */
44
+ private $_leaseId;
45
+
46
+ /**
47
+ * @var string
48
+ */
49
+ private $_snapshot;
50
+
51
+ /**
52
+ * @var integer
53
+ */
54
+ private $_rangeStart;
55
+
56
+ /**
57
+ * @var integer
58
+ */
59
+ private $_rangeEnd;
60
+
61
+ /**
62
+ * @var AccessCondition
63
+ */
64
+ private $_accessCondition;
65
+
66
+ /**
67
+ * Gets lease Id for the blob
68
+ *
69
+ * @return string
70
+ */
71
+ public function getLeaseId()
72
+ {
73
+ return $this->_leaseId;
74
+ }
75
+
76
+ /**
77
+ * Sets lease Id for the blob
78
+ *
79
+ * @param string $leaseId the blob lease id.
80
+ *
81
+ * @return none
82
+ */
83
+ public function setLeaseId($leaseId)
84
+ {
85
+ $this->_leaseId = $leaseId;
86
+ }
87
+
88
+ /**
89
+ * Gets blob snapshot.
90
+ *
91
+ * @return string.
92
+ */
93
+ public function getSnapshot()
94
+ {
95
+ return $this->_snapshot;
96
+ }
97
+
98
+ /**
99
+ * Sets blob snapshot.
100
+ *
101
+ * @param string $snapshot value.
102
+ *
103
+ * @return none.
104
+ */
105
+ public function setSnapshot($snapshot)
106
+ {
107
+ $this->_snapshot = $snapshot;
108
+ }
109
+
110
+ /**
111
+ * Gets rangeStart
112
+ *
113
+ * @return integer
114
+ */
115
+ public function getRangeStart()
116
+ {
117
+ return $this->_rangeStart;
118
+ }
119
+
120
+ /**
121
+ * Sets rangeStart
122
+ *
123
+ * @param integer $rangeStart the blob lease id.
124
+ *
125
+ * @return none
126
+ */
127
+ public function setRangeStart($rangeStart)
128
+ {
129
+ Validate::isInteger($rangeStart, 'rangeStart');
130
+ $this->_rangeStart = $rangeStart;
131
+ }
132
+
133
+ /**
134
+ * Gets rangeEnd
135
+ *
136
+ * @return integer
137
+ */
138
+ public function getRangeEnd()
139
+ {
140
+ return $this->_rangeEnd;
141
+ }
142
+
143
+ /**
144
+ * Sets rangeEnd
145
+ *
146
+ * @param integer $rangeEnd range end value in bytes
147
+ *
148
+ * @return none
149
+ */
150
+ public function setRangeEnd($rangeEnd)
151
+ {
152
+ Validate::isInteger($rangeEnd, 'rangeEnd');
153
+ $this->_rangeEnd = $rangeEnd;
154
+ }
155
+
156
+ /**
157
+ * Gets access condition
158
+ *
159
+ * @return AccessCondition
160
+ */
161
+ public function getAccessCondition()
162
+ {
163
+ return $this->_accessCondition;
164
+ }
165
+
166
+ /**
167
+ * Sets access condition
168
+ *
169
+ * @param AccessCondition $accessCondition value to use.
170
+ *
171
+ * @return none.
172
+ */
173
+ public function setAccessCondition($accessCondition)
174
+ {
175
+ $this->_accessCondition = $accessCondition;
176
+ }
177
+ }
178
+
179
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/ListPageBlobRangesResult.php ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
27
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
28
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
29
+ use MicrosoftAzure\Storage\Blob\Models\PageRange;
30
+
31
+ /**
32
+ * Holds result of calling listPageBlobRanges wrapper
33
+ *
34
+ * @category Microsoft
35
+ * @package MicrosoftAzure\Storage\Blob\Models
36
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
37
+ * @copyright 2016 Microsoft Corporation
38
+ * @license https://github.com/azure/azure-storage-php/LICENSE
39
+ * @version Release: 0.11.0
40
+ * @link https://github.com/azure/azure-storage-php
41
+ */
42
+ class ListPageBlobRangesResult
43
+ {
44
+ /**
45
+ * @var \DateTime
46
+ */
47
+ private $_lastModified;
48
+
49
+ /**
50
+ * @var string
51
+ */
52
+ private $_etag;
53
+
54
+ /**
55
+ * @var integer
56
+ */
57
+ private $_contentLength;
58
+
59
+ /**
60
+ * @var array
61
+ */
62
+ private $_pageRanges;
63
+
64
+ /**
65
+ * Creates BlobProperties object from $parsed response in array representation
66
+ *
67
+ * @param array $headers HTTP response headers
68
+ * @param array $parsed parsed response in array format.
69
+ *
70
+ * @return ListPageBlobRangesResult
71
+ */
72
+ public static function create($headers, $parsed)
73
+ {
74
+ $result = new ListPageBlobRangesResult();
75
+ $headers = array_change_key_case($headers);
76
+
77
+ $date = $headers[Resources::LAST_MODIFIED];
78
+ $date = Utilities::rfc1123ToDateTime($date);
79
+ $blobLength = intval($headers[Resources::X_MS_BLOB_CONTENT_LENGTH]);
80
+ $rawPageRanges = array();
81
+
82
+ if (!empty($parsed['PageRange'])) {
83
+ $parsed = array_change_key_case($parsed);
84
+ $rawPageRanges = Utilities::getArray($parsed['pagerange']);
85
+ }
86
+
87
+ $result->_pageRanges = array();
88
+ foreach ($rawPageRanges as $value) {
89
+ $result->_pageRanges[] = new PageRange(
90
+ intval($value['Start']), intval($value['End'])
91
+ );
92
+ }
93
+
94
+ $result->setContentLength($blobLength);
95
+ $result->setETag($headers[Resources::ETAG]);
96
+ $result->setLastModified($date);
97
+
98
+ return $result;
99
+ }
100
+
101
+ /**
102
+ * Gets blob lastModified.
103
+ *
104
+ * @return \DateTime.
105
+ */
106
+ public function getLastModified()
107
+ {
108
+ return $this->_lastModified;
109
+ }
110
+
111
+ /**
112
+ * Sets blob lastModified.
113
+ *
114
+ * @param \DateTime $lastModified value.
115
+ *
116
+ * @return none.
117
+ */
118
+ public function setLastModified($lastModified)
119
+ {
120
+ Validate::isDate($lastModified);
121
+ $this->_lastModified = $lastModified;
122
+ }
123
+
124
+ /**
125
+ * Gets blob etag.
126
+ *
127
+ * @return string.
128
+ */
129
+ public function getETag()
130
+ {
131
+ return $this->_etag;
132
+ }
133
+
134
+ /**
135
+ * Sets blob etag.
136
+ *
137
+ * @param string $etag value.
138
+ *
139
+ * @return none.
140
+ */
141
+ public function setETag($etag)
142
+ {
143
+ Validate::isString($etag, 'etag');
144
+ $this->_etag = $etag;
145
+ }
146
+
147
+ /**
148
+ * Gets blob contentLength.
149
+ *
150
+ * @return integer.
151
+ */
152
+ public function getContentLength()
153
+ {
154
+ return $this->_contentLength;
155
+ }
156
+
157
+ /**
158
+ * Sets blob contentLength.
159
+ *
160
+ * @param integer $contentLength value.
161
+ *
162
+ * @return none.
163
+ */
164
+ public function setContentLength($contentLength)
165
+ {
166
+ Validate::isInteger($contentLength, 'contentLength');
167
+ $this->_contentLength = $contentLength;
168
+ }
169
+
170
+ /**
171
+ * Gets page ranges
172
+ *
173
+ * @return array
174
+ */
175
+ public function getPageRanges()
176
+ {
177
+ return $this->_pageRanges;
178
+ }
179
+
180
+ /**
181
+ * Sets page ranges
182
+ *
183
+ * @param array $pageRanges page ranges to set
184
+ *
185
+ * @return none
186
+ */
187
+ public function setPageRanges($pageRanges)
188
+ {
189
+ $this->_pageRanges = array();
190
+ foreach ($pageRanges as $pageRange) {
191
+ $this->_pageRanges[] = clone $pageRange;
192
+ }
193
+ }
194
+ }
195
+
196
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/PageRange.php ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Holds info about page range used in HTTP requests
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class PageRange
39
+ {
40
+ /**
41
+ * @var integer
42
+ */
43
+ private $_start;
44
+
45
+ /**
46
+ * @var integer
47
+ */
48
+ private $_end;
49
+
50
+ /**
51
+ * Constructor
52
+ *
53
+ * @param integer $start the page start value
54
+ * @param integer $end the page end value
55
+ *
56
+ * @return PageRange
57
+ */
58
+ public function __construct($start = null, $end = null)
59
+ {
60
+ $this->_start = $start;
61
+ $this->_end = $end;
62
+ }
63
+
64
+ /**
65
+ * Sets page start range
66
+ *
67
+ * @param integer $start the page range start
68
+ *
69
+ * @return none.
70
+ */
71
+ public function setStart($start)
72
+ {
73
+ $this->_start = $start;
74
+ }
75
+
76
+ /**
77
+ * Gets page start range
78
+ *
79
+ * @return integer
80
+ */
81
+ public function getStart()
82
+ {
83
+ return $this->_start;
84
+ }
85
+
86
+ /**
87
+ * Sets page end range
88
+ *
89
+ * @param integer $end the page range end
90
+ *
91
+ * @return none.
92
+ */
93
+ public function setEnd($end)
94
+ {
95
+ $this->_end = $end;
96
+ }
97
+
98
+ /**
99
+ * Gets page end range
100
+ *
101
+ * @return integer
102
+ */
103
+ public function getEnd()
104
+ {
105
+ return $this->_end;
106
+ }
107
+
108
+ /**
109
+ * Gets page range length
110
+ *
111
+ * @return integer
112
+ */
113
+ public function getLength()
114
+ {
115
+ return $this->_end - $this->_start + 1;
116
+ }
117
+
118
+ /**
119
+ * Sets page range length
120
+ *
121
+ * @param integer $value new page range
122
+ *
123
+ * @return none
124
+ */
125
+ public function setLength($value)
126
+ {
127
+ $this->_end = $this->_start + $value - 1;
128
+ }
129
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/PageWriteOption.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * Holds available blob page write options
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class PageWriteOption
39
+ {
40
+ const CLEAR_OPTION = 'clear';
41
+ const UPDATE_OPTION = 'update';
42
+ }
43
+
44
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/PublicAccessType.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
27
+
28
+ /**
29
+ * Holds public acces types for a container.
30
+ *
31
+ * @category Microsoft
32
+ * @package MicrosoftAzure\Storage\Blob\Models
33
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
34
+ * @copyright 2016 Microsoft Corporation
35
+ * @license https://github.com/azure/azure-storage-php/LICENSE
36
+ * @version Release: 0.11.0
37
+ * @link https://github.com/azure/azure-storage-php
38
+ */
39
+ class PublicAccessType
40
+ {
41
+ const NONE = Resources::EMPTY_STRING;
42
+ const BLOBS_ONLY = 'blob';
43
+ const CONTAINER_AND_BLOBS = 'container';
44
+
45
+ /**
46
+ * Validates the public access.
47
+ *
48
+ * @param string $type The public access type.
49
+ *
50
+ * @return boolean
51
+ */
52
+ public static function isValid($type)
53
+ {
54
+ switch ($type) {
55
+ case self::NONE:
56
+ case self::BLOBS_ONLY:
57
+ case self::CONTAINER_AND_BLOBS:
58
+ return true;
59
+
60
+ default:
61
+ return false;
62
+ }
63
+ }
64
+ }
65
+
66
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/SetBlobMetadataOptions.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ /**
28
+ * The optional parameters for setBlobMetadata API.
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Blob\Models
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class SetBlobMetadataOptions extends BlobServiceOptions
39
+ {
40
+ /**
41
+ * @var string
42
+ */
43
+ private $_leaseId;
44
+
45
+ /**
46
+ * @var AccessCondition
47
+ */
48
+ private $_accessCondition;
49
+
50
+ /**
51
+ * Gets lease Id for the blob
52
+ *
53
+ * @return string
54
+ */
55
+ public function getLeaseId()
56
+ {
57
+ return $this->_leaseId;
58
+ }
59
+
60
+ /**
61
+ * Sets lease Id for the blob
62
+ *
63
+ * @param string $leaseId the blob lease id.
64
+ *
65
+ * @return none
66
+ */
67
+ public function setLeaseId($leaseId)
68
+ {
69
+ $this->_leaseId = $leaseId;
70
+ }
71
+
72
+ /**
73
+ * Gets access condition
74
+ *
75
+ * @return AccessCondition
76
+ */
77
+ public function getAccessCondition()
78
+ {
79
+ return $this->_accessCondition;
80
+ }
81
+
82
+ /**
83
+ * Sets access condition
84
+ *
85
+ * @param AccessCondition $accessCondition value to use.
86
+ *
87
+ * @return none.
88
+ */
89
+ public function setAccessCondition($accessCondition)
90
+ {
91
+ $this->_accessCondition = $accessCondition;
92
+ }
93
+ }
94
+
95
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/SetBlobMetadataResult.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
27
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
28
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
29
+
30
+ /**
31
+ * Holds results of calling getBlobMetadata wrapper
32
+ *
33
+ * @category Microsoft
34
+ * @package MicrosoftAzure\Storage\Blob\Models
35
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
36
+ * @copyright 2016 Microsoft Corporation
37
+ * @license https://github.com/azure/azure-storage-php/LICENSE
38
+ * @version Release: 0.11.0
39
+ * @link https://github.com/azure/azure-storage-php
40
+ */
41
+ class SetBlobMetadataResult
42
+ {
43
+
44
+ /**
45
+ * @var \DateTime
46
+ */
47
+ private $_lastModified;
48
+
49
+ /**
50
+ * @var string
51
+ */
52
+ private $_etag;
53
+
54
+ /**
55
+ * Creates SetBlobMetadataResult from response headers.
56
+ *
57
+ * @param array $headers response headers
58
+ *
59
+ * @return SetBlobMetadataResult
60
+ */
61
+ public static function create($headers)
62
+ {
63
+ $result = new SetBlobMetadataResult();
64
+ $date = $headers[Resources::LAST_MODIFIED];
65
+ $result->setLastModified(Utilities::rfc1123ToDateTime($date));
66
+ $result->setETag($headers[Resources::ETAG]);
67
+
68
+ return $result;
69
+ }
70
+
71
+ /**
72
+ * Gets blob lastModified.
73
+ *
74
+ * @return \DateTime.
75
+ */
76
+ public function getLastModified()
77
+ {
78
+ return $this->_lastModified;
79
+ }
80
+
81
+ /**
82
+ * Sets blob lastModified.
83
+ *
84
+ * @param \DateTime $lastModified value.
85
+ *
86
+ * @return none.
87
+ */
88
+ public function setLastModified($lastModified)
89
+ {
90
+ Validate::isDate($lastModified);
91
+ $this->_lastModified = $lastModified;
92
+ }
93
+
94
+ /**
95
+ * Gets blob etag.
96
+ *
97
+ * @return string.
98
+ */
99
+ public function getETag()
100
+ {
101
+ return $this->_etag;
102
+ }
103
+
104
+ /**
105
+ * Sets blob etag.
106
+ *
107
+ * @param string $etag value.
108
+ *
109
+ * @return none.
110
+ */
111
+ public function setETag($etag)
112
+ {
113
+ Validate::isString($etag, 'etag');
114
+ $this->_etag = $etag;
115
+ }
116
+ }
117
+
118
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/SetBlobPropertiesOptions.php ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
27
+
28
+ /**
29
+ * Optional parameters for setBlobProperties wrapper
30
+ *
31
+ * @category Microsoft
32
+ * @package MicrosoftAzure\Storage\Blob\Models
33
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
34
+ * @copyright 2016 Microsoft Corporation
35
+ * @license https://github.com/azure/azure-storage-php/LICENSE
36
+ * @version Release: 0.11.0
37
+ * @link https://github.com/azure/azure-storage-php
38
+ */
39
+ class SetBlobPropertiesOptions extends BlobServiceOptions
40
+ {
41
+ /**
42
+ * @var BlobProperties
43
+ */
44
+ private $_blobProperties;
45
+
46
+ /**
47
+ * @var string
48
+ */
49
+ private $_leaseId;
50
+
51
+ /**
52
+ * @var string
53
+ */
54
+ private $_sequenceNumberAction;
55
+
56
+ /**
57
+ * @var AccessCondition
58
+ */
59
+ private $_accessCondition;
60
+
61
+ /**
62
+ * Creates a new SetBlobPropertiesOptions with a specified BlobProperties
63
+ * instance.
64
+ *
65
+ * @param BlobProperties $blobProperties The blob properties instance.
66
+ */
67
+ public function __construct($blobProperties = null)
68
+ {
69
+ $this->_blobProperties = is_null($blobProperties)
70
+ ? new BlobProperties() : clone $blobProperties;
71
+ }
72
+
73
+ /**
74
+ * Gets access condition
75
+ *
76
+ * @return AccessCondition
77
+ */
78
+ public function getAccessCondition()
79
+ {
80
+ return $this->_accessCondition;
81
+ }
82
+
83
+ /**
84
+ * Sets access condition
85
+ *
86
+ * @param AccessCondition $accessCondition value to use.
87
+ *
88
+ * @return none.
89
+ */
90
+ public function setAccessCondition($accessCondition)
91
+ {
92
+ $this->_accessCondition = $accessCondition;
93
+ }
94
+
95
+ /**
96
+ * Gets blob sequenceNumber.
97
+ *
98
+ * @return integer.
99
+ */
100
+ public function getSequenceNumber()
101
+ {
102
+ return $this->_blobProperties->getSequenceNumber();
103
+ }
104
+
105
+ /**
106
+ * Sets blob sequenceNumber.
107
+ *
108
+ * @param integer $sequenceNumber value.
109
+ *
110
+ * @return none.
111
+ */
112
+ public function setSequenceNumber($sequenceNumber)
113
+ {
114
+ $this->_blobProperties->setSequenceNumber($sequenceNumber);
115
+ }
116
+
117
+ /**
118
+ * Gets lease Id for the blob
119
+ *
120
+ * @return string
121
+ */
122
+ public function getSequenceNumberAction()
123
+ {
124
+ return $this->_sequenceNumberAction;
125
+ }
126
+
127
+ /**
128
+ * Sets lease Id for the blob
129
+ *
130
+ * @param string $sequenceNumberAction action.
131
+ *
132
+ * @return none
133
+ */
134
+ public function setSequenceNumberAction($sequenceNumberAction)
135
+ {
136
+ $this->_sequenceNumberAction = $sequenceNumberAction;
137
+ }
138
+
139
+ /**
140
+ * Gets lease Id for the blob
141
+ *
142
+ * @return string
143
+ */
144
+ public function getLeaseId()
145
+ {
146
+ return $this->_leaseId;
147
+ }
148
+
149
+ /**
150
+ * Sets lease Id for the blob
151
+ *
152
+ * @param string $leaseId the blob lease id.
153
+ *
154
+ * @return none
155
+ */
156
+ public function setLeaseId($leaseId)
157
+ {
158
+ $this->_leaseId = $leaseId;
159
+ }
160
+
161
+ /**
162
+ * Gets blob blobContentLength.
163
+ *
164
+ * @return integer.
165
+ */
166
+ public function getBlobContentLength()
167
+ {
168
+ return $this->_blobProperties->getContentLength();
169
+ }
170
+
171
+ /**
172
+ * Sets blob blobContentLength.
173
+ *
174
+ * @param integer $blobContentLength value.
175
+ *
176
+ * @return none.
177
+ */
178
+ public function setBlobContentLength($blobContentLength)
179
+ {
180
+ $this->_blobProperties->setContentLength($blobContentLength);
181
+ }
182
+
183
+ /**
184
+ * Gets blob ContentType.
185
+ *
186
+ * @return string.
187
+ */
188
+ public function getBlobContentType()
189
+ {
190
+ return $this->_blobProperties->getContentType();
191
+ }
192
+
193
+ /**
194
+ * Sets blob ContentType.
195
+ *
196
+ * @param string $blobContentType value.
197
+ *
198
+ * @return none.
199
+ */
200
+ public function setBlobContentType($blobContentType)
201
+ {
202
+ $this->_blobProperties->setContentType($blobContentType);
203
+ }
204
+
205
+ /**
206
+ * Gets blob ContentEncoding.
207
+ *
208
+ * @return string.
209
+ */
210
+ public function getBlobContentEncoding()
211
+ {
212
+ return $this->_blobProperties->getContentEncoding();
213
+ }
214
+
215
+ /**
216
+ * Sets blob ContentEncoding.
217
+ *
218
+ * @param string $blobContentEncoding value.
219
+ *
220
+ * @return none.
221
+ */
222
+ public function setBlobContentEncoding($blobContentEncoding)
223
+ {
224
+ $this->_blobProperties->setContentEncoding($blobContentEncoding);
225
+ }
226
+
227
+ /**
228
+ * Gets blob ContentLanguage.
229
+ *
230
+ * @return string.
231
+ */
232
+ public function getBlobContentLanguage()
233
+ {
234
+ return $this->_blobProperties->getContentLanguage();
235
+ }
236
+
237
+ /**
238
+ * Sets blob ContentLanguage.
239
+ *
240
+ * @param string $blobContentLanguage value.
241
+ *
242
+ * @return none.
243
+ */
244
+ public function setBlobContentLanguage($blobContentLanguage)
245
+ {
246
+ $this->_blobProperties->setContentLanguage($blobContentLanguage);
247
+ }
248
+
249
+ /**
250
+ * Gets blob ContentMD5.
251
+ *
252
+ * @return string.
253
+ */
254
+ public function getBlobContentMD5()
255
+ {
256
+ return $this->_blobProperties->getContentMD5();
257
+ }
258
+
259
+ /**
260
+ * Sets blob ContentMD5.
261
+ *
262
+ * @param string $blobContentMD5 value.
263
+ *
264
+ * @return none.
265
+ */
266
+ public function setBlobContentMD5($blobContentMD5)
267
+ {
268
+ $this->_blobProperties->setContentMD5($blobContentMD5);
269
+ }
270
+
271
+ /**
272
+ * Gets blob cache control.
273
+ *
274
+ * @return string.
275
+ */
276
+ public function getBlobCacheControl()
277
+ {
278
+ return $this->_blobProperties->getCacheControl();
279
+ }
280
+
281
+ /**
282
+ * Sets blob cacheControl.
283
+ *
284
+ * @param string $blobCacheControl value to use.
285
+ *
286
+ * @return none.
287
+ */
288
+ public function setBlobCacheControl($blobCacheControl)
289
+ {
290
+ $this->_blobProperties->setCacheControl($blobCacheControl);
291
+ }
292
+ }
lib/Azure/MicrosoftAzureStorage/Blob/Models/SetBlobPropertiesResult.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
27
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
28
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
29
+
30
+ /**
31
+ * Holds result of calling setBlobProperties wrapper
32
+ *
33
+ * @category Microsoft
34
+ * @package MicrosoftAzure\Storage\Blob\Models
35
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
36
+ * @copyright 2016 Microsoft Corporation
37
+ * @license https://github.com/azure/azure-storage-php/LICENSE
38
+ * @version Release: 0.11.0
39
+ * @link https://github.com/azure/azure-storage-php
40
+ */
41
+ class SetBlobPropertiesResult
42
+ {
43
+ /**
44
+ * @var \DateTime
45
+ */
46
+ private $_lastModified;
47
+
48
+ /**
49
+ * @var string
50
+ */
51
+ private $_etag;
52
+
53
+ /**
54
+ * @var integer
55
+ */
56
+ private $_sequenceNumber;
57
+
58
+ /**
59
+ * Creates SetBlobPropertiesResult from response headers.
60
+ *
61
+ * @param array $headers response headers
62
+ *
63
+ * @return SetBlobPropertiesResult
64
+ */
65
+ public static function create($headers)
66
+ {
67
+ $result = new SetBlobPropertiesResult();
68
+ $date = $headers[Resources::LAST_MODIFIED];
69
+ $result->setLastModified(Utilities::rfc1123ToDateTime($date));
70
+ $result->setETag($headers[Resources::ETAG]);
71
+ if (array_key_exists(Resources::X_MS_BLOB_SEQUENCE_NUMBER, $headers)) {
72
+ $sNumber = $headers[Resources::X_MS_BLOB_SEQUENCE_NUMBER];
73
+ $result->setSequenceNumber(intval($sNumber));
74
+ }
75
+
76
+ return $result;
77
+ }
78
+
79
+ /**
80
+ * Gets blob lastModified.
81
+ *
82
+ * @return \DateTime.
83
+ */
84
+ public function getLastModified()
85
+ {
86
+ return $this->_lastModified;
87
+ }
88
+
89
+ /**
90
+ * Sets blob lastModified.
91
+ *
92
+ * @param \DateTime $lastModified value.
93
+ *
94
+ * @return none.
95
+ */
96
+ public function setLastModified($lastModified)
97
+ {
98
+ Validate::isDate($lastModified);
99
+ $this->_lastModified = $lastModified;
100
+ }
101
+
102
+ /**
103
+ * Gets blob etag.
104
+ *
105
+ * @return string.
106
+ */
107
+ public function getETag()
108
+ {
109
+ return $this->_etag;
110
+ }
111
+
112
+ /**
113
+ * Sets blob etag.
114
+ *
115
+ * @param string $etag value.
116
+ *
117
+ * @return none.
118
+ */
119
+ public function setETag($etag)
120
+ {
121
+ Validate::isString($etag, 'etag');
122
+ $this->_etag = $etag;
123
+ }
124
+
125
+ /**
126
+ * Gets blob sequenceNumber.
127
+ *
128
+ * @return int.
129
+ */
130
+ public function getSequenceNumber()
131
+ {
132
+ return $this->_sequenceNumber;
133
+ }
134
+
135
+ /**
136
+ * Sets blob sequenceNumber.
137
+ *
138
+ * @param int $sequenceNumber value.
139
+ *
140
+ * @return none.
141
+ */
142
+ public function setSequenceNumber($sequenceNumber)
143
+ {
144
+ Validate::isInteger($sequenceNumber, 'sequenceNumber');
145
+ $this->_sequenceNumber = $sequenceNumber;
146
+ }
147
+ }
148
+
149
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/SetContainerMetadataOptions.php ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+ use MicrosoftAzure\Storage\Blob\Models\AccessCondition;
27
+ use MicrosoftAzure\Storage\Blob\Models\BlobServiceOptions;
28
+
29
+ /**
30
+ * Optional parameters for setContainerMetadata wrapper
31
+ *
32
+ * @category Microsoft
33
+ * @package MicrosoftAzure\Storage\Blob\Models
34
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
35
+ * @copyright 2016 Microsoft Corporation
36
+ * @license https://github.com/azure/azure-storage-php/LICENSE
37
+ * @version Release: 0.11.0
38
+ * @link https://github.com/azure/azure-storage-php
39
+ */
40
+ class SetContainerMetadataOptions extends BlobServiceOptions
41
+ {
42
+ /**
43
+ * @var AccessCondition
44
+ */
45
+ private $_accessCondition;
46
+
47
+ /**
48
+ * Constructs the access condition object with none option.
49
+ */
50
+ public function __construct()
51
+ {
52
+ $this->_accessCondition = AccessCondition::none();
53
+ }
54
+
55
+ /**
56
+ * Gets access condition
57
+ *
58
+ * @return AccessCondition
59
+ */
60
+ public function getAccessCondition()
61
+ {
62
+ return $this->_accessCondition;
63
+ }
64
+
65
+ /**
66
+ * Sets access condition
67
+ *
68
+ * @param AccessCondition $accessCondition value to use.
69
+ *
70
+ * @return none.
71
+ */
72
+ public function setAccessCondition($accessCondition)
73
+ {
74
+ $this->_accessCondition = $accessCondition;
75
+ }
76
+ }
77
+
78
+
lib/Azure/MicrosoftAzureStorage/Blob/Models/SignedIdentifier.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Blob\Models
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Blob\Models;
26
+
27
+ use MicrosoftAzure\Storage\Blob\Models\AccessPolicy;
28
+
29
+ /**
30
+ * Holds container signed identifiers.
31
+ *
32
+ * @category Microsoft
33
+ * @package MicrosoftAzure\Storage\Blob\Models
34
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
35
+ * @copyright 2016 Microsoft Corporation
36
+ * @license https://github.com/azure/azure-storage-php/LICENSE
37
+ * @version Release: 0.11.0
38
+ * @link https://github.com/azure/azure-storage-php
39
+ */
40
+ class SignedIdentifier
41
+ {
42
+ private $_id;
43
+ private $_accessPolicy;
44
+
45
+ /**
46
+ * Gets id.
47
+ *
48
+ * @return string.
49
+ */
50
+ public function getId()
51
+ {
52
+ return $this->_id;
53
+ }
54
+
55
+ /**
56
+ * Sets id.
57
+ *
58
+ * @param string $id value.
59
+ *
60
+ * @return none.
61
+ */
62
+ public function setId($id)
63
+ {
64
+ $this->_id = $id;
65
+ }
66
+
67
+ /**
68
+ * Gets accessPolicy.
69
+ *
70
+ * @return string.
71
+ */
72
+ public function getAccessPolicy()
73
+ {
74
+ return $this->_accessPolicy;
75
+ }
76
+
77
+ /**
78
+ * Sets accessPolicy.
79
+ *
80
+ * @param string $accessPolicy value.
81
+ *
82
+ * @return none.
83
+ */
84
+ public function setAccessPolicy($accessPolicy)
85
+ {
86
+ $this->_accessPolicy = $accessPolicy;
87
+ }
88
+
89
+ /**
90
+ * Converts this current object to XML representation.
91
+ *
92
+ * @return array.
93
+ */
94
+ public function toArray()
95
+ {
96
+ $array = array();
97
+
98
+ $array['SignedIdentifier']['Id'] = $this->_id;
99
+ $array['SignedIdentifier']['AccessPolicy'] = $this->_accessPolicy->toArray();
100
+
101
+ return $array;
102
+ }
103
+ }
lib/Azure/MicrosoftAzureStorage/Common/CloudConfigurationManager.php ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common;
26
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
27
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
28
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
29
+ use MicrosoftAzure\Storage\Common\Internal\ConnectionStringSource;
30
+
31
+ /**
32
+ * Configuration manager for accessing Windows Azure settings.
33
+ *
34
+ * @category Microsoft
35
+ * @package MicrosoftAzure\Storage\Common
36
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
37
+ * @copyright 2016 Microsoft Corporation
38
+ * @license https://github.com/azure/azure-storage-php/LICENSE
39
+ * @version Release: 0.11.0
40
+ * @link https://github.com/azure/azure-storage-php
41
+ */
42
+ class CloudConfigurationManager
43
+ {
44
+ /**
45
+ * @var boolean
46
+ */
47
+ private static $_isInitialized = false;
48
+
49
+ /**
50
+ * The list of connection string sources.
51
+ *
52
+ * @var array
53
+ */
54
+ private static $_sources;
55
+
56
+ /**
57
+ * Restrict users from creating instances from this class
58
+ */
59
+ private function __construct()
60
+ {
61
+
62
+ }
63
+
64
+ /**
65
+ * Initializes the connection string source providers.
66
+ *
67
+ * @return none
68
+ */
69
+ private static function _init()
70
+ {
71
+ if (!self::$_isInitialized) {
72
+ self::$_sources = array();
73
+
74
+ // Get list of default connection string sources.
75
+ $default = ConnectionStringSource::getDefaultSources();
76
+ foreach ($default as $name => $provider) {
77
+ self::$_sources[$name] = $provider;
78
+ }
79
+
80
+ self::$_isInitialized = true;
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Gets a connection string from all available sources.
86
+ *
87
+ * @param string $key The connection string key name.
88
+ *
89
+ * @return string If the key does not exist return null.
90
+ */
91
+ public static function getConnectionString($key)
92
+ {
93
+ Validate::isString($key, 'key');
94
+
95
+ self::_init();
96
+ $value = null;
97
+
98
+ foreach (self::$_sources as $source) {
99
+ $value = call_user_func_array($source, array($key));
100
+
101
+ if (!empty($value)) {
102
+ break;
103
+ }
104
+ }
105
+
106
+ return $value;
107
+ }
108
+
109
+ /**
110
+ * Registers a new connection string source provider. If the source to get
111
+ * registered is a default source, only the name of the source is required.
112
+ *
113
+ * @param string $name The source name.
114
+ * @param callable $provider The source callback.
115
+ * @param boolean $prepend When true, the $provider is processed first when
116
+ * calling getConnectionString. When false (the default) the $provider is
117
+ * processed after the existing callbacks.
118
+ *
119
+ * @return none
120
+ */
121
+ public static function registerSource($name, $provider = null, $prepend = false)
122
+ {
123
+ Validate::isString($name, 'name');
124
+ Validate::notNullOrEmpty($name, 'name');
125
+
126
+ self::_init();
127
+ $default = ConnectionStringSource::getDefaultSources();
128
+
129
+ // Try to get callback if the user is trying to register a default source.
130
+ $provider = Utilities::tryGetValue($default, $name, $provider);
131
+
132
+ Validate::notNullOrEmpty($provider, 'callback');
133
+
134
+ if ($prepend) {
135
+ self::$_sources = array_merge(
136
+ array($name => $provider),
137
+ self::$_sources
138
+ );
139
+
140
+ } else {
141
+ self::$_sources[$name] = $provider;
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Unregisters a connection string source.
147
+ *
148
+ * @param string $name The source name.
149
+ *
150
+ * @return callable
151
+ */
152
+ public static function unregisterSource($name)
153
+ {
154
+ Validate::isString($name, 'name');
155
+ Validate::notNullOrEmpty($name, 'name');
156
+
157
+ self::_init();
158
+
159
+ $sourceCallback = Utilities::tryGetValue(self::$_sources, $name);
160
+
161
+ if (!is_null($sourceCallback)) {
162
+ unset(self::$_sources[$name]);
163
+ }
164
+
165
+ return $sourceCallback;
166
+ }
167
+ }
lib/Azure/MicrosoftAzureStorage/Common/Internal/Authentication/IAuthScheme.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal\Authentication
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal\Authentication;
26
+
27
+ /**
28
+ * Interface for azure authentication schemes.
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Common\Internal\Authentication
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ interface IAuthScheme
39
+ {
40
+ /**
41
+ * Returns authorization header to be included in the request.
42
+ *
43
+ * @param array $headers request headers.
44
+ * @param string $url reuqest url.
45
+ * @param array $queryParams query variables.
46
+ * @param string $httpMethod request http method.
47
+ *
48
+ * @see Specifying the Authorization Header section at
49
+ * http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
50
+ *
51
+ * @abstract
52
+ *
53
+ * @return string
54
+ */
55
+ public function getAuthorizationHeader($headers, $url, $queryParams,
56
+ $httpMethod
57
+ );
58
+ }
59
+
60
+
lib/Azure/MicrosoftAzureStorage/Common/Internal/Authentication/SharedKeyAuthScheme.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal\Authentication
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal\Authentication;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\Authentication\StorageAuthScheme;
28
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
29
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
30
+
31
+ /**
32
+ * Provides shared key authentication scheme for blob and queue. For more info
33
+ * check: http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
34
+ *
35
+ * @category Microsoft
36
+ * @package MicrosoftAzure\Storage\Common\Internal\Authentication
37
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
38
+ * @copyright 2016 Microsoft Corporation
39
+ * @license https://github.com/azure/azure-storage-php/LICENSE
40
+ * @version Release: 0.11.0
41
+ * @link https://github.com/azure/azure-storage-php
42
+ */
43
+ class SharedKeyAuthScheme extends StorageAuthScheme
44
+ {
45
+ protected $includedHeaders;
46
+
47
+ /**
48
+ * Constructor.
49
+ *
50
+ * @param string $accountName storage account name.
51
+ * @param string $accountKey storage account primary or secondary key.
52
+ *
53
+ * @return
54
+ * MicrosoftAzure\Storage\Common\Internal\Authentication\SharedKeyAuthScheme
55
+ */
56
+ public function __construct($accountName, $accountKey)
57
+ {
58
+ parent::__construct($accountName, $accountKey);
59
+
60
+ $this->includedHeaders = array();
61
+ $this->includedHeaders[] = Resources::CONTENT_ENCODING;
62
+ $this->includedHeaders[] = Resources::CONTENT_LANGUAGE;
63
+ $this->includedHeaders[] = Resources::CONTENT_LENGTH;
64
+ $this->includedHeaders[] = Resources::CONTENT_MD5;
65
+ $this->includedHeaders[] = Resources::CONTENT_TYPE;
66
+ $this->includedHeaders[] = Resources::DATE;
67
+ $this->includedHeaders[] = Resources::IF_MODIFIED_SINCE;
68
+ $this->includedHeaders[] = Resources::IF_MATCH;
69
+ $this->includedHeaders[] = Resources::IF_NONE_MATCH;
70
+ $this->includedHeaders[] = Resources::IF_UNMODIFIED_SINCE;
71
+ $this->includedHeaders[] = Resources::RANGE;
72
+ }
73
+
74
+ /**
75
+ * Computes the authorization signature for blob and queue shared key.
76
+ *
77
+ * @param array $headers request headers.
78
+ * @param string $url reuqest url.
79
+ * @param array $queryParams query variables.
80
+ * @param string $httpMethod request http method.
81
+ *
82
+ * @see Blob and Queue Services (Shared Key Authentication) at
83
+ * http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
84
+ *
85
+ * @return string
86
+ */
87
+ protected function computeSignature($headers, $url, $queryParams, $httpMethod)
88
+ {
89
+ $canonicalizedHeaders = parent::computeCanonicalizedHeaders($headers);
90
+
91
+ $canonicalizedResource = parent::computeCanonicalizedResource(
92
+ $url,
93
+ $queryParams
94
+ );
95
+
96
+ $stringToSign = array();
97
+ $stringToSign[] = strtoupper($httpMethod);
98
+
99
+ foreach ($this->includedHeaders as $header) {
100
+ $stringToSign[] = Utilities::tryGetValue($headers, $header);
101
+ }
102
+
103
+ if (count($canonicalizedHeaders) > 0) {
104
+ $stringToSign[] = implode("\n", $canonicalizedHeaders);
105
+ }
106
+
107
+ $stringToSign[] = $canonicalizedResource;
108
+ $stringToSign = implode("\n", $stringToSign);
109
+
110
+ return $stringToSign;
111
+ }
112
+
113
+ /**
114
+ * Returns authorization header to be included in the request.
115
+ *
116
+ * @param array $headers request headers.
117
+ * @param string $url reuqest url.
118
+ * @param array $queryParams query variables.
119
+ * @param string $httpMethod request http method.
120
+ *
121
+ * @see Specifying the Authorization Header section at
122
+ * http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
123
+ *
124
+ * @return string
125
+ */
126
+ public function getAuthorizationHeader($headers, $url, $queryParams, $httpMethod)
127
+ {
128
+ $signature = $this->computeSignature(
129
+ $headers,
130
+ $url,
131
+ $queryParams,
132
+ $httpMethod
133
+ );
134
+
135
+ return 'SharedKey ' . $this->accountName . ':' . base64_encode(
136
+ hash_hmac('sha256', $signature, base64_decode($this->accountKey), true)
137
+ );
138
+ }
139
+ }
lib/Azure/MicrosoftAzureStorage/Common/Internal/Authentication/StorageAuthScheme.php ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal\Authentication
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal\Authentication;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
28
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
29
+ use MicrosoftAzure\Storage\Common\Internal\Authentication\IAuthScheme;
30
+
31
+ /**
32
+ * Base class for azure authentication schemes.
33
+ *
34
+ * @category Microsoft
35
+ * @package MicrosoftAzure\Storage\Common\Internal\Authentication
36
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
37
+ * @copyright 2016 Microsoft Corporation
38
+ * @license https://github.com/azure/azure-storage-php/LICENSE
39
+ * @version Release: 0.11.0
40
+ * @link https://github.com/azure/azure-storage-php
41
+ */
42
+ abstract class StorageAuthScheme implements IAuthScheme
43
+ {
44
+ protected $accountName;
45
+ protected $accountKey;
46
+
47
+ /**
48
+ * Constructor.
49
+ *
50
+ * @param string $accountName storage account name.
51
+ * @param string $accountKey storage account primary or secondary key.
52
+ *
53
+ * @return
54
+ * MicrosoftAzure\Storage\Common\Internal\Authentication\StorageAuthScheme
55
+ */
56
+ public function __construct($accountName, $accountKey)
57
+ {
58
+ $this->accountKey = $accountKey;
59
+ $this->accountName = $accountName;
60
+ }
61
+
62
+ /**
63
+ * Computes canonicalized headers for headers array.
64
+ *
65
+ * @param array $headers request headers.
66
+ *
67
+ * @see Constructing the Canonicalized Headers String section at
68
+ * http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
69
+ *
70
+ * @return array
71
+ */
72
+ protected function computeCanonicalizedHeaders($headers)
73
+ {
74
+ $canonicalizedHeaders = array();
75
+ $normalizedHeaders = array();
76
+ $validPrefix = Resources::X_MS_HEADER_PREFIX;
77
+
78
+ if (is_null($normalizedHeaders)) {
79
+ return $canonicalizedHeaders;
80
+ }
81
+
82
+ foreach ($headers as $header => $value) {
83
+ // Convert header to lower case.
84
+ $header = strtolower($header);
85
+
86
+ // Retrieve all headers for the resource that begin with x-ms-,
87
+ // including the x-ms-date header.
88
+ if (Utilities::startsWith($header, $validPrefix)) {
89
+ // Unfold the string by replacing any breaking white space
90
+ // (meaning what splits the headers, which is \r\n) with a single
91
+ // space.
92
+ $value = str_replace("\r\n", ' ', $value);
93
+
94
+ // Trim any white space around the colon in the header.
95
+ $value = ltrim($value);
96
+ $header = rtrim($header);
97
+
98
+ $normalizedHeaders[$header] = $value;
99
+ }
100
+ }
101
+
102
+ // Sort the headers lexicographically by header name, in ascending order.
103
+ // Note that each header may appear only once in the string.
104
+ ksort($normalizedHeaders);
105
+
106
+ foreach ($normalizedHeaders as $key => $value) {
107
+ $canonicalizedHeaders[] = $key . ':' . $value;
108
+ }
109
+
110
+ return $canonicalizedHeaders;
111
+ }
112
+
113
+ /**
114
+ * Computes canonicalized resources from URL using Table formar
115
+ *
116
+ * @param string $url request url.
117
+ * @param array $queryParams request query variables.
118
+ *
119
+ * @see Constructing the Canonicalized Resource String section at
120
+ * http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
121
+ *
122
+ * @return string
123
+ */
124
+ protected function computeCanonicalizedResourceForTable($url, $queryParams)
125
+ {
126
+ $queryParams = array_change_key_case($queryParams);
127
+
128
+ // 1. Beginning with an empty string (""), append a forward slash (/),
129
+ // followed by the name of the account that owns the accessed resource.
130
+ $canonicalizedResource = '/' . $this->accountName;
131
+
132
+ // 2. Append the resource's encoded URI path, without any query parameters.
133
+ $canonicalizedResource .= parse_url($url, PHP_URL_PATH);
134
+
135
+ // 3. The query string should include the question mark and the comp
136
+ // parameter (for example, ?comp=metadata). No other parameters should
137
+ // be included on the query string.
138
+ if (array_key_exists(Resources::QP_COMP, $queryParams)) {
139
+ $canonicalizedResource .= '?' . Resources::QP_COMP . '=';
140
+ $canonicalizedResource .= $queryParams[Resources::QP_COMP];
141
+ }
142
+
143
+ return $canonicalizedResource;
144
+ }
145
+
146
+ /**
147
+ * Computes canonicalized resources from URL.
148
+ *
149
+ * @param string $url request url.
150
+ * @param array $queryParams request query variables.
151
+ *
152
+ * @see Constructing the Canonicalized Resource String section at
153
+ * http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
154
+ *
155
+ * @return string
156
+ */
157
+ protected function computeCanonicalizedResource($url, $queryParams)
158
+ {
159
+ $queryParams = array_change_key_case($queryParams);
160
+
161
+ // 1. Beginning with an empty string (""), append a forward slash (/),
162
+ // followed by the name of the account that owns the accessed resource.
163
+ $canonicalizedResource = '/' . $this->accountName;
164
+
165
+ // 2. Append the resource's encoded URI path, without any query parameters.
166
+ $canonicalizedResource .= parse_url($url, PHP_URL_PATH);
167
+
168
+ // 3. Retrieve all query parameters on the resource URI, including the comp
169
+ // parameter if it exists.
170
+ // 4. Sort the query parameters lexicographically by parameter name, in
171
+ // ascending order.
172
+ if (count($queryParams) > 0) {
173
+ ksort($queryParams);
174
+ }
175
+
176
+ // 5. Convert all parameter names to lowercase.
177
+ // 6. URL-decode each query parameter name and value.
178
+ // 7. Append each query parameter name and value to the string in the
179
+ // following format:
180
+ // parameter-name:parameter-value
181
+ // 9. Group query parameters
182
+ // 10. Append a new line character (\n) after each name-value pair.
183
+ foreach ($queryParams as $key => $value) {
184
+ // $value must already be ordered lexicographically
185
+ // See: ServiceRestProxy::groupQueryValues
186
+ $canonicalizedResource .= "\n" . $key . ':' . $value;
187
+ }
188
+
189
+ return $canonicalizedResource;
190
+ }
191
+
192
+ /**
193
+ * Computes the authorization signature.
194
+ *
195
+ * @param array $headers request headers.
196
+ * @param string $url reuqest url.
197
+ * @param array $queryParams query variables.
198
+ * @param string $httpMethod request http method.
199
+ *
200
+ * @see check all authentication schemes at
201
+ * http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
202
+ *
203
+ * @abstract
204
+ *
205
+ * @return string
206
+ */
207
+ abstract protected function computeSignature(
208
+ $headers,
209
+ $url,
210
+ $queryParams,
211
+ $httpMethod
212
+ );
213
+ }
lib/Azure/MicrosoftAzureStorage/Common/Internal/Authentication/TableSharedKeyLiteAuthScheme.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal\Authentication
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link http://github.com/windowsazure/azure-sdk-for-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal\Authentication;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\Authentication\StorageAuthScheme;
28
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
29
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
30
+
31
+ /**
32
+ * Provides shared key authentication scheme for blob and queue. For more info
33
+ * check: http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
34
+ *
35
+ * @category Microsoft
36
+ * @package MicrosoftAzure\Storage\Common\Internal\Authentication
37
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
38
+ * @copyright 2016 Microsoft Corporation
39
+ * @license https://github.com/azure/azure-storage-php/LICENSE
40
+ * @version Release: 0.11.0
41
+ * @link http://github.com/windowsazure/azure-sdk-for-php
42
+ */
43
+ class TableSharedKeyLiteAuthScheme extends StorageAuthScheme
44
+ {
45
+ protected $includedHeaders;
46
+
47
+ /**
48
+ * Constructor.
49
+ *
50
+ * @param string $accountName storage account name.
51
+ * @param string $accountKey storage account primary or secondary key.
52
+ *
53
+ * @return TableSharedKeyLiteAuthScheme
54
+ */
55
+ public function __construct($accountName, $accountKey)
56
+ {
57
+ parent::__construct($accountName, $accountKey);
58
+
59
+ $this->includedHeaders = array();
60
+ $this->includedHeaders[] = Resources::DATE;
61
+ }
62
+
63
+ /**
64
+ * Computes the authorization signature for blob and queue shared key.
65
+ *
66
+ * @param array $headers request headers.
67
+ * @param string $url reuqest url.
68
+ * @param array $queryParams query variables.
69
+ * @param string $httpMethod request http method.
70
+ *
71
+ * @see Blob and Queue Services (Shared Key Authentication) at
72
+ * http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
73
+ *
74
+ * @return string
75
+ */
76
+ protected function computeSignature($headers, $url, $queryParams, $httpMethod)
77
+ {
78
+ $canonicalizedResource = parent::computeCanonicalizedResourceForTable(
79
+ $url,
80
+ $queryParams
81
+ );
82
+
83
+ $stringToSign = array();
84
+
85
+ foreach ($this->includedHeaders as $header) {
86
+ $stringToSign[] = Utilities::tryGetValue($headers, $header);
87
+ }
88
+
89
+ $stringToSign[] = $canonicalizedResource;
90
+ $stringToSign = implode("\n", $stringToSign);
91
+
92
+ return $stringToSign;
93
+ }
94
+
95
+ /**
96
+ * Returns authorization header to be included in the request.
97
+ *
98
+ * @param array $headers request headers.
99
+ * @param string $url reuqest url.
100
+ * @param array $queryParams query variables.
101
+ * @param string $httpMethod request http method.
102
+ *
103
+ * @see Specifying the Authorization Header section at
104
+ * http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
105
+ *
106
+ * @return string
107
+ */
108
+ public function getAuthorizationHeader($headers, $url, $queryParams, $httpMethod)
109
+ {
110
+ $signature = $this->computeSignature(
111
+ $headers,
112
+ $url,
113
+ $queryParams,
114
+ $httpMethod
115
+ );
116
+
117
+ return 'SharedKeyLite ' . $this->accountName . ':' . base64_encode(
118
+ hash_hmac('sha256', $signature, base64_decode($this->accountKey), true)
119
+ );
120
+ }
121
+ }
lib/Azure/MicrosoftAzureStorage/Common/Internal/ConnectionStringParser.php ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal;
26
+
27
+ /**
28
+ * Helper methods for parsing connection strings. The rules for formatting connection
29
+ * strings are defined here:
30
+ * www.connectionstrings.com/articles/show/important-rules-for-connection-strings
31
+ *
32
+ * @category Microsoft
33
+ * @package MicrosoftAzure\Storage\Common\Internal
34
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
35
+ * @copyright 2016 Microsoft Corporation
36
+ * @license https://github.com/azure/azure-storage-php/LICENSE
37
+ * @version Release: 0.11.0
38
+ * @link https://github.com/azure/azure-storage-php
39
+ */
40
+ class ConnectionStringParser
41
+ {
42
+ const EXPECT_KEY = 'ExpectKey';
43
+ const EXPECT_ASSIGNMENT = 'ExpectAssignment';
44
+ const EXPECT_VALUE = 'ExpectValue';
45
+ const EXPECT_SEPARATOR = 'ExpectSeparator';
46
+
47
+ /**
48
+ * @var string
49
+ */
50
+ private $_argumentName;
51
+
52
+ /**
53
+ * @var string
54
+ */
55
+ private $_value;
56
+
57
+ /**
58
+ * @var integer
59
+ */
60
+ private $_pos;
61
+
62
+ /**
63
+ * @var string
64
+ */
65
+ private $_state;
66
+
67
+ /**
68
+ * Parses the connection string into a collection of key/value pairs.
69
+ *
70
+ * @param string $argumentName Name of the argument to be used in error
71
+ * messages.
72
+ * @param string $connectionString Connection string.
73
+ *
74
+ * @return array
75
+ *
76
+ * @static
77
+ */
78
+ public static function parseConnectionString($argumentName, $connectionString)
79
+ {
80
+ Validate::isString($argumentName, 'argumentName');
81
+ Validate::notNullOrEmpty($argumentName, 'argumentName');
82
+ Validate::isString($connectionString, 'connectionString');
83
+ Validate::notNullOrEmpty($connectionString, 'connectionString');
84
+
85
+ $parser = new ConnectionStringParser($argumentName, $connectionString);
86
+ return $parser->_parse();
87
+ }
88
+
89
+ /**
90
+ * Initializes the object.
91
+ *
92
+ * @param string $argumentName Name of the argument to be used in error
93
+ * messages.
94
+ * @param string $value Connection string.
95
+ */
96
+ private function __construct($argumentName, $value)
97
+ {
98
+ $this->_argumentName = $argumentName;
99
+ $this->_value = $value;
100
+ $this->_pos = 0;
101
+ $this->_state = ConnectionStringParser::EXPECT_KEY;
102
+ }
103
+
104
+ /**
105
+ * Parses the connection string.
106
+ *
107
+ * @return array
108
+ *
109
+ * @throws \RuntimeException
110
+ */
111
+ private function _parse()
112
+ {
113
+ $key = null;
114
+ $value = null;
115
+ $connectionStringValues = array();
116
+
117
+ while (true) {
118
+ $this->_skipWhiteSpaces();
119
+
120
+ if ($this->_pos == strlen($this->_value)
121
+ && $this->_state != ConnectionStringParser::EXPECT_VALUE
122
+ ) {
123
+ // Not stopping after the end has been reached and a value is
124
+ // expected results in creating an empty value, which we expect.
125
+ break;
126
+ }
127
+
128
+ switch ($this->_state) {
129
+ case ConnectionStringParser::EXPECT_KEY:
130
+ $key = $this->_extractKey();
131
+ $this->_state = ConnectionStringParser::EXPECT_ASSIGNMENT;
132
+ break;
133
+
134
+ case ConnectionStringParser::EXPECT_ASSIGNMENT:
135
+ $this->_skipOperator('=');
136
+ $this->_state = ConnectionStringParser::EXPECT_VALUE;
137
+ break;
138
+
139
+ case ConnectionStringParser::EXPECT_VALUE:
140
+ $value = $this->_extractValue();
141
+ $this->_state =
142
+ ConnectionStringParser::EXPECT_SEPARATOR;
143
+ $connectionStringValues[$key] = $value;
144
+ $key = null;
145
+ $value = null;
146
+ break;
147
+
148
+ default:
149
+ $this->_skipOperator(';');
150
+ $this->_state = ConnectionStringParser::EXPECT_KEY;
151
+ break;
152
+ }
153
+ }
154
+
155
+ // Must end parsing in the valid state (expected key or separator)
156
+ if ($this->_state == ConnectionStringParser::EXPECT_ASSIGNMENT) {
157
+ throw $this->_createException(
158
+ $this->_pos,
159
+ Resources::MISSING_CONNECTION_STRING_CHAR,
160
+ '='
161
+ );
162
+ }
163
+
164
+ return $connectionStringValues;
165
+ }
166
+
167
+ /**
168
+ *Generates an invalid connection string exception with the detailed error
169
+ * message.
170
+ *
171
+ * @param integer $position The position of the error.
172
+ * @param string $errorString The short error formatting string.
173
+ *
174
+ * @return \RuntimeException
175
+ */
176
+ private function _createException($position, $errorString)
177
+ {
178
+ $arguments = func_get_args();
179
+
180
+ // Remove first and second arguments (position and error string)
181
+ unset($arguments[0], $arguments[1]);
182
+
183
+ // Create a short error message.
184
+ $errorString = vsprintf($errorString, $arguments);
185
+
186
+ // Add position.
187
+ $errorString = sprintf(
188
+ Resources::ERROR_PARSING_STRING,
189
+ $errorString,
190
+ $position
191
+ );
192
+
193
+ // Create final error message.
194
+ $errorString = sprintf(
195
+ Resources::INVALID_CONNECTION_STRING,
196
+ $this->_argumentName,
197
+ $errorString
198
+ );
199
+
200
+ return new \RuntimeException($errorString);
201
+ }
202
+
203
+ /**
204
+ * Skips whitespaces at the current position.
205
+ *
206
+ * @return none
207
+ */
208
+ private function _skipWhiteSpaces()
209
+ {
210
+ while ($this->_pos < strlen($this->_value)
211
+ && ctype_space($this->_value[$this->_pos])
212
+ ) {
213
+ $this->_pos++;
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Extracts the key's value.
219
+ *
220
+ * @return string
221
+ */
222
+ private function _extractValue()
223
+ {
224
+ $value = Resources::EMPTY_STRING;
225
+
226
+ if ($this->_pos < strlen($this->_value)) {
227
+ $ch = $this->_value[$this->_pos];
228
+
229
+ if ($ch == '"' || $ch == '\'') {
230
+ // Value is contained between double quotes or skipped single quotes.
231
+ $this->_pos++;
232
+ $value = $this->_extractString($ch);
233
+ } else {
234
+ $firstPos = $this->_pos;
235
+ $isFound = false;
236
+
237
+ while ($this->_pos < strlen($this->_value) && !$isFound) {
238
+ $ch = $this->_value[$this->_pos];
239
+
240
+ if ($ch == ';') {
241
+ $isFound = true;
242
+ } else {
243
+ $this->_pos++;
244
+ }
245
+ }
246
+
247
+ $value = rtrim(
248
+ substr($this->_value, $firstPos, $this->_pos - $firstPos)
249
+ );
250
+ }
251
+ }
252
+
253
+ return $value;
254
+ }
255
+
256
+ /**
257
+ * Extracts key at the current position.
258
+ *
259
+ * @return string
260
+ */
261
+ private function _extractKey()
262
+ {
263
+ $key = null;
264
+ $firstPos = $this->_pos;
265
+ $ch = $this->_value[$this->_pos];
266
+
267
+ if ($ch == '"' || $ch == '\'') {
268
+ $this->_pos++;
269
+ $key = $this->_extractString($ch);
270
+ } else if ($ch == ';' || $ch == '=') {
271
+ // Key name was expected.
272
+ throw $this->_createException(
273
+ $firstPos,
274
+ Resources::ERROR_CONNECTION_STRING_MISSING_KEY
275
+ );
276
+ } else {
277
+ while ($this->_pos < strlen($this->_value)) {
278
+ $ch = $this->_value[$this->_pos];
279
+
280
+ // At this point we've read the key, break.
281
+ if ($ch == '=') {
282
+ break;
283
+ }
284
+
285
+ $this->_pos++;
286
+ }
287
+ $key = rtrim(substr($this->_value, $firstPos, $this->_pos - $firstPos));
288
+ }
289
+
290
+ if (strlen($key) == 0) {
291
+ // Empty key name.
292
+ throw $this->_createException(
293
+ $firstPos,
294
+ Resources::ERROR_CONNECTION_STRING_EMPTY_KEY
295
+ );
296
+ }
297
+
298
+ return $key;
299
+ }
300
+
301
+ /**
302
+ * Extracts the string until the given quotation mark.
303
+ *
304
+ * @param string $quote The quotation mark terminating the string.
305
+ *
306
+ * @return string
307
+ */
308
+ private function _extractString($quote)
309
+ {
310
+ $firstPos = $this->_pos;
311
+
312
+ while ($this->_pos < strlen($this->_value)
313
+ && $this->_value[$this->_pos] != $quote
314
+ ) {
315
+ $this->_pos++;
316
+ }
317
+
318
+ if ($this->_pos == strlen($this->_value)) {
319
+ // Runaway string.
320
+ throw $this->_createException(
321
+ $this->_pos,
322
+ Resources::ERROR_CONNECTION_STRING_MISSING_CHARACTER,
323
+ $quote
324
+ );
325
+ }
326
+
327
+ return substr($this->_value, $firstPos, $this->_pos++ - $firstPos);
328
+ }
329
+
330
+ /**
331
+ * Skips specified operator.
332
+ *
333
+ * @param string $operatorChar The operator character.
334
+ *
335
+ * @return none
336
+ *
337
+ * @throws \RuntimeException
338
+ */
339
+ private function _skipOperator($operatorChar)
340
+ {
341
+ if ($this->_value[$this->_pos] != $operatorChar) {
342
+ // Character was expected.
343
+ throw $this->_createException(
344
+ $this->_pos,
345
+ Resources::MISSING_CONNECTION_STRING_CHAR,
346
+ $operatorChar
347
+ );
348
+ }
349
+
350
+ $this->_pos++;
351
+ }
352
+ }
lib/Azure/MicrosoftAzureStorage/Common/Internal/ConnectionStringSource.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal;
26
+
27
+ /**
28
+ * Holder for default connection string sources used in CloudConfigurationManager.
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Common\Internal
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class ConnectionStringSource
39
+ {
40
+ /**
41
+ * The list of all sources which comes as default.
42
+ *
43
+ * @var type
44
+ */
45
+ private static $_defaultSources;
46
+
47
+ /**
48
+ * @var boolean
49
+ */
50
+ private static $_isInitialized;
51
+
52
+ /**
53
+ * Environment variable source name.
54
+ */
55
+ const ENVIRONMENT_SOURCE = 'environment_source';
56
+
57
+ /**
58
+ * Initializes the default sources.
59
+ *
60
+ * @return none
61
+ */
62
+ private static function _init()
63
+ {
64
+ if (!self::$_isInitialized) {
65
+ self::$_defaultSources = array(
66
+ self::ENVIRONMENT_SOURCE => array(__CLASS__, 'environmentSource')
67
+ );
68
+ self::$_isInitialized = true;
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Gets a connection string value from the system environment.
74
+ *
75
+ * @param string $key The connection string name.
76
+ *
77
+ * @return string
78
+ */
79
+ public static function environmentSource($key)
80
+ {
81
+ Validate::isString($key, 'key');
82
+
83
+ return getenv($key);
84
+ }
85
+
86
+ /**
87
+ * Gets list of default sources.
88
+ *
89
+ * @return array
90
+ */
91
+ public static function getDefaultSources()
92
+ {
93
+ self::_init();
94
+ return self::$_defaultSources;
95
+ }
96
+ }
97
+
98
+
lib/Azure/MicrosoftAzureStorage/Common/Internal/FilterableService.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal;
26
+
27
+ /**
28
+ * Interface for service with filers.
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Common\Internal
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ interface FilterableService
39
+ {
40
+ /**
41
+ * Adds new filter to proxy object and returns new BlobRestProxy with
42
+ * that filter.
43
+ *
44
+ * @param MicrosoftAzure\Storage\Common\Internal\IServiceFilter $filter Filter to add for
45
+ * the pipeline.
46
+ *
47
+ * @return mix.
48
+ */
49
+ public function withFilter($filter);
50
+ }
51
+
52
+
lib/Azure/MicrosoftAzureStorage/Common/Internal/Filters/AuthenticationFilter.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal\Filters
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal\Filters;
26
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
27
+ use MicrosoftAzure\Storage\Common\Internal\IServiceFilter;
28
+ use MicrosoftAzure\Storage\Common\Internal\HttpFormatter;
29
+ use GuzzleHttp\Psr7;
30
+
31
+ /**
32
+ * Adds authentication header to the http request object.
33
+ *
34
+ * @category Microsoft
35
+ * @package MicrosoftAzure\Storage\Common\Internal\Filters
36
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
37
+ * @copyright 2016 Microsoft Corporation
38
+ * @license https://github.com/azure/azure-storage-php/LICENSE
39
+ * @version Release: 0.11.0
40
+ * @link https://github.com/azure/azure-storage-php
41
+ */
42
+ class AuthenticationFilter implements IServiceFilter
43
+ {
44
+ /**
45
+ * @var MicrosoftAzure\Storage\Common\Internal\Authentication\StorageAuthScheme
46
+ */
47
+ private $_authenticationScheme;
48
+
49
+ /**
50
+ * Creates AuthenticationFilter with the passed scheme.
51
+ *
52
+ * @param StorageAuthScheme $authenticationScheme The authentication scheme.
53
+ */
54
+ public function __construct($authenticationScheme)
55
+ {
56
+ $this->_authenticationScheme = $authenticationScheme;
57
+ }
58
+
59
+ /**
60
+ * Adds authentication header to the request headers.
61
+ *
62
+ * @param \GuzzleHttp\Psr7\Request $request HTTP request object.
63
+ *
64
+ * @return \GuzzleHttp\Psr7\Request
65
+ */
66
+ public function handleRequest($request)
67
+ {
68
+ $requestHeaders = HttpFormatter::formatHeaders($request->getHeaders());
69
+
70
+ $signedKey = $this->_authenticationScheme->getAuthorizationHeader(
71
+ $requestHeaders, $request->getUri(),
72
+ \GuzzleHttp\Psr7\parse_query($request->getUri()->getQuery()), $request->getMethod()
73
+ );
74
+ return $request->withHeader(Resources::AUTHENTICATION, $signedKey);
75
+ }
76
+
77
+ /**
78
+ * Does nothing with the response.
79
+ *
80
+ * @param \GuzzleHttp\Psr7\Request $request HTTP request object.
81
+ * @param \GuzzleHttp\Psr7\Response $response HTTP response object.
82
+ *
83
+ * @return \GuzzleHttp\Psr7\Response
84
+ */
85
+ public function handleResponse($request, $response)
86
+ {
87
+ // Do nothing with the response.
88
+ return $response;
89
+ }
90
+ }
91
+
92
+
lib/Azure/MicrosoftAzureStorage/Common/Internal/Filters/DateFilter.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal\Filters
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal\Filters;
26
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
27
+ use MicrosoftAzure\Storage\Common\Internal\IServiceFilter;
28
+
29
+ /**
30
+ * Adds date header to the http request.
31
+ *
32
+ * @category Microsoft
33
+ * @package MicrosoftAzure\Storage\Common\Internal\Filters
34
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
35
+ * @copyright 2016 Microsoft Corporation
36
+ * @license https://github.com/azure/azure-storage-php/LICENSE
37
+ * @version Release: 0.11.0
38
+ * @link https://github.com/azure/azure-storage-php
39
+ */
40
+ class DateFilter implements IServiceFilter
41
+ {
42
+ /**
43
+ * Adds date (in GMT format) header to the request headers.
44
+ *
45
+ * @param \GuzzleHttp\Psr7\Request $request HTTP request object.
46
+ *
47
+ * @return \GuzzleHttp\Psr7\Request
48
+ */
49
+ public function handleRequest($request)
50
+ {
51
+ $date = gmdate(Resources::AZURE_DATE_FORMAT, time());
52
+ return $request->withHeader(Resources::DATE, $date);
53
+ }
54
+
55
+ /**
56
+ * Does nothing with the response.
57
+ *
58
+ * @param \GuzzleHttp\Psr7\Request $request HTTP request object.
59
+ * @param \GuzzleHttp\Psr7\Response $response HTTP response object.
60
+ *
61
+ * @return \GuzzleHttp\Psr7\Request\Response
62
+ */
63
+ public function handleResponse($request, $response)
64
+ {
65
+ // Do nothing with the response.
66
+ return $response;
67
+ }
68
+ }
69
+
70
+
lib/Azure/MicrosoftAzureStorage/Common/Internal/Filters/ExponentialRetryPolicy.php ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal\Filters
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal\Filters;
26
+
27
+ /**
28
+ * The exponential retry policy.
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Common\Internal\Filters
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class ExponentialRetryPolicy extends RetryPolicy
39
+ {
40
+ /**
41
+ * @var integer
42
+ */
43
+ private $_deltaBackoffIntervalInMs;
44
+
45
+ /**
46
+ * @var integer
47
+ */
48
+ private $_maximumAttempts;
49
+
50
+ /**
51
+ * @var integer
52
+ */
53
+ private $_resolvedMaxBackoff;
54
+
55
+ /**
56
+ * @var integer
57
+ */
58
+ private $_resolvedMinBackoff;
59
+
60
+ /**
61
+ * @var array
62
+ */
63
+ private $_retryableStatusCodes;
64
+
65
+ /**
66
+ * Initializes new object from ExponentialRetryPolicy.
67
+ *
68
+ * @param array $retryableStatusCodes The retryable status codes.
69
+ * @param integer $deltaBackoff The backoff time delta.
70
+ * @param integer $maximumAttempts The number of max attempts.
71
+ */
72
+ public function __construct($retryableStatusCodes,
73
+ $deltaBackoff = parent::DEFAULT_CLIENT_BACKOFF,
74
+ $maximumAttempts = parent::DEFAULT_CLIENT_RETRY_COUNT
75
+ ) {
76
+ $this->_deltaBackoffIntervalInMs = $deltaBackoff;
77
+ $this->_maximumAttempts = $maximumAttempts;
78
+ $this->_resolvedMaxBackoff = parent::DEFAULT_MAX_BACKOFF;
79
+ $this->_resolvedMinBackoff = parent::DEFAULT_MIN_BACKOFF;
80
+ $this->_retryableStatusCodes = $retryableStatusCodes;
81
+ sort($retryableStatusCodes);
82
+ }
83
+
84
+ /**
85
+ * Indicates if there should be a retry or not.
86
+ *
87
+ * @param integer $retryCount The retry count.
88
+ * @param \GuzzleHttp\Psr7\Response $response The HTTP response object.
89
+ *
90
+ * @return boolean
91
+ */
92
+ public function shouldRetry($retryCount, $response)
93
+ {
94
+ if ( $retryCount >= $this->_maximumAttempts
95
+ || array_search($response->getStatusCode(), $this->_retryableStatusCodes)
96
+ || is_null($response)
97
+ ) {
98
+ return false;
99
+ } else {
100
+ return true;
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Calculates the backoff for the retry policy.
106
+ *
107
+ * @param integer $retryCount The retry count.
108
+ * @param \GuzzleHttp\Psr7\Response $response The HTTP response object.
109
+ *
110
+ * @return integer
111
+ */
112
+ public function calculateBackoff($retryCount, $response)
113
+ {
114
+ // Calculate backoff Interval between 80% and 120% of the desired
115
+ // backoff, multiply by 2^n -1 for
116
+ // exponential
117
+ $incrementDelta = (int) (pow(2, $retryCount) - 1);
118
+ $boundedRandDelta = (int) ($this->_deltaBackoffIntervalInMs * 0.8)
119
+ + mt_rand(
120
+ 0,
121
+ (int) ($this->_deltaBackoffIntervalInMs * 1.2)
122
+ - (int) ($this->_deltaBackoffIntervalInMs * 0.8)
123
+ );
124
+ $incrementDelta *= $boundedRandDelta;
125
+
126
+ // Enforce max / min backoffs
127
+ return min(
128
+ $this->_resolvedMinBackoff + $incrementDelta,
129
+ $this->_resolvedMaxBackoff
130
+ );
131
+ }
132
+ }
133
+
134
+
lib/Azure/MicrosoftAzureStorage/Common/Internal/Filters/HeadersFilter.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal\Filters
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal\Filters;
26
+ use MicrosoftAzure\Storage\Common\Internal\IServiceFilter;
27
+
28
+ /**
29
+ * Adds all passed headers to the HTTP request headers.
30
+ *
31
+ * @category Microsoft
32
+ * @package MicrosoftAzure\Storage\Common\Internal\Filters
33
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
34
+ * @copyright 2016 Microsoft Corporation
35
+ * @license https://github.com/azure/azure-storage-php/LICENSE
36
+ * @version Release: 0.11.0
37
+ * @link https://github.com/azure/azure-storage-php
38
+ */
39
+ class HeadersFilter implements IServiceFilter
40
+ {
41
+ /**
42
+ * @var array
43
+ */
44
+ private $_headers;
45
+
46
+ /**
47
+ * Constructor
48
+ *
49
+ * @param array $headers static headers to be added.
50
+ *
51
+ * @return HeadersFilter
52
+ */
53
+ public function __construct($headers)
54
+ {
55
+ $this->_headers = $headers;
56
+ }
57
+
58
+ /**
59
+ * Adds static header(s) to the HTTP request headers
60
+ *
61
+ * @param \GuzzleHttp\Psr7\Request $request HTTP request object.
62
+ *
63
+ * @return \GuzzleHttp\Psr7\Request
64
+ */
65
+ public function handleRequest($request)
66
+ {
67
+ $result = $request;
68
+
69
+ foreach ($this->_headers as $key => $value) {
70
+ $headers = $request->getHeaders();
71
+ if (!array_key_exists($key, $headers)) {
72
+ $result = $result->withHeader($key, $value);
73
+ }
74
+ }
75
+
76
+ return $result;
77
+ }
78
+
79
+ /**
80
+ * Does nothing with the response.
81
+ *
82
+ * @param \GuzzleHttp\Psr7\Request $request HTTP request object.
83
+ * @param \GuzzleHttp\Psr7\Response $response HTTP response object.
84
+ *
85
+ * @return \GuzzleHttp\Psr7\Response
86
+ */
87
+ public function handleResponse($request, $response)
88
+ {
89
+ // Do nothing with the response.
90
+ return $response;
91
+ }
92
+ }
93
+
94
+
lib/Azure/MicrosoftAzureStorage/Common/Internal/Filters/RetryPolicy.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal\Filters
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal\Filters;
26
+
27
+ /**
28
+ * The retry policy abstract class.
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Common\Internal\Filters
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ abstract class RetryPolicy
39
+ {
40
+ const DEFAULT_CLIENT_BACKOFF = 30000;
41
+ const DEFAULT_CLIENT_RETRY_COUNT = 3;
42
+ const DEFAULT_MAX_BACKOFF = 90000;
43
+ const DEFAULT_MIN_BACKOFF = 300;
44
+
45
+ /**
46
+ * Indicates if there should be a retry or not.
47
+ *
48
+ * @param integer $retryCount The retry count.
49
+ * @param \GuzzleHttp\Psr7\Response $response The HTTP response object.
50
+ *
51
+ * @return boolean
52
+ */
53
+ public abstract function shouldRetry($retryCount, $response);
54
+
55
+ /**
56
+ * Calculates the backoff for the retry policy.
57
+ *
58
+ * @param integer $retryCount The retry count.
59
+ * @param \GuzzleHttp\Psr7\Response $response The HTTP response object.
60
+ *
61
+ * @return integer
62
+ */
63
+ public abstract function calculateBackoff($retryCount, $response);
64
+ }
65
+
66
+
lib/Azure/MicrosoftAzureStorage/Common/Internal/Filters/RetryPolicyFilter.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal\Filters
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal\Filters;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\IServiceFilter;
28
+ use GuzzleHttp\Client;
29
+
30
+ /**
31
+ * Short description
32
+ *
33
+ * @category Microsoft
34
+ * @package MicrosoftAzure\Storage\Common\Internal\Filters
35
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
36
+ * @copyright 2016 Microsoft Corporation
37
+ * @license https://github.com/azure/azure-storage-php/LICENSE
38
+ * @version Release: 0.11.0
39
+ * @link https://github.com/azure/azure-storage-php
40
+ */
41
+ class RetryPolicyFilter implements IServiceFilter
42
+ {
43
+ /**
44
+ * @var RetryPolicy
45
+ */
46
+ private $_retryPolicy;
47
+
48
+ /**
49
+ * @var \GuzzleHttp\Client
50
+ */
51
+ private $_client;
52
+
53
+ /**
54
+ * Initializes new object from RetryPolicyFilter.
55
+ *
56
+ * @param \GuzzleHttp\Client $client The http client to send request.
57
+ * @param RetryPolicy $retryPolicy The retry policy object.
58
+ */
59
+ public function __construct($client, $retryPolicy)
60
+ {
61
+ $this->_client = $client;
62
+ $this->_retryPolicy = $retryPolicy;
63
+ }
64
+
65
+ /**
66
+ * Handles the request before sending.
67
+ *
68
+ * @param \GuzzleHttp\Psr7\Request $request The HTTP request.
69
+ *
70
+ * @return \GuzzleHttp\Psr7\Request
71
+ */
72
+ public function handleRequest($request)
73
+ {
74
+ return $request;
75
+ }
76
+
77
+ /**
78
+ * Handles the response after sending.
79
+ *
80
+ * @param \GuzzleHttp\Psr7\Request $request The HTTP request.
81
+ * @param \GuzzleHttp\Psr7\Response $response The HTTP response.
82
+ *
83
+ * @return \GuzzleHttp\Psr7\Response
84
+ */
85
+ public function handleResponse($request, $response)
86
+ {
87
+ for ($retryCount = 0;; $retryCount++) {
88
+ $shouldRetry = $this->_retryPolicy->shouldRetry(
89
+ $retryCount,
90
+ $response
91
+ );
92
+
93
+ if (!$shouldRetry) {
94
+ return $response;
95
+ }
96
+
97
+ // Backoff for some time according to retry policy
98
+ $backoffTime = $this->_retryPolicy->calculateBackoff(
99
+ $retryCount,
100
+ $response
101
+ );
102
+ sleep($backoffTime * 0.001);
103
+ $response = $this->_client->send($request);
104
+ }
105
+ }
106
+ }
lib/Azure/MicrosoftAzureStorage/Common/Internal/Http/HttpCallContext.php ADDED
@@ -0,0 +1,449 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal\Http
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal\Http;
26
+ use MicrosoftAzure\Storage\Common\Internal\Utilities;
27
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
28
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
29
+
30
+ /**
31
+ * Holds basic elements for making HTTP call.
32
+ *
33
+ * @category Microsoft
34
+ * @package MicrosoftAzure\Storage\Common\Internal\Http
35
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
36
+ * @copyright 2016 Microsoft Corporation
37
+ * @license https://github.com/azure/azure-storage-php/LICENSE
38
+ * @version Release: 0.11.0
39
+ * @link https://github.com/azure/azure-storage-php
40
+ */
41
+ class HttpCallContext
42
+ {
43
+ /**
44
+ * The HTTP method used to make this call.
45
+ *
46
+ * @var string
47
+ */
48
+ private $_method;
49
+
50
+ /**
51
+ * HTTP request headers.
52
+ *
53
+ * @var array
54
+ */
55
+ private $_headers;
56
+
57
+ /**
58
+ * The URI query parameters.
59
+ *
60
+ * @var array
61
+ */
62
+ private $_queryParams;
63
+
64
+ /**
65
+ * The HTTP POST parameters.
66
+ *
67
+ * @var array.
68
+ */
69
+ private $_postParameters;
70
+
71
+ /**
72
+ * @var string
73
+ */
74
+ private $_uri;
75
+
76
+ /**
77
+ * The URI path.
78
+ *
79
+ * @var string
80
+ */
81
+ private $_path;
82
+
83
+ /**
84
+ * The expected status codes.
85
+ *
86
+ * @var array
87
+ */
88
+ private $_statusCodes;
89
+
90
+ /**
91
+ * The HTTP request body.
92
+ *
93
+ * @var string
94
+ */
95
+ private $_body;
96
+
97
+ /**
98
+ * Default constructor.
99
+ */
100
+ public function __construct()
101
+ {
102
+ $this->_method = null;
103
+ $this->_body = null;
104
+ $this->_path = null;
105
+ $this->_uri = null;
106
+ $this->_queryParams = array();
107
+ $this->_postParameters = array();
108
+ $this->_statusCodes = array();
109
+ $this->_headers = array();
110
+ }
111
+
112
+ /**
113
+ * Gets method.
114
+ *
115
+ * @return string
116
+ */
117
+ public function getMethod()
118
+ {
119
+ return $this->_method;
120
+ }
121
+
122
+ /**
123
+ * Sets method.
124
+ *
125
+ * @param string $method The method value.
126
+ *
127
+ * @return none
128
+ */
129
+ public function setMethod($method)
130
+ {
131
+ Validate::isString($method, 'method');
132
+
133
+ $this->_method = $method;
134
+ }
135
+
136
+ /**
137
+ * Gets headers.
138
+ *
139
+ * @return array
140
+ */
141
+ public function getHeaders()
142
+ {
143
+ return $this->_headers;
144
+ }
145
+
146
+ /**
147
+ * Sets headers.
148
+ *
149
+ * Ignores the header if its value is empty.
150
+ *
151
+ * @param array $headers The headers value.
152
+ *
153
+ * @return none
154
+ */
155
+ public function setHeaders($headers)
156
+ {
157
+ $this->_headers = array();
158
+ foreach ($headers as $key => $value) {
159
+ $this->addHeader($key, $value);
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Gets queryParams.
165
+ *
166
+ * @return array
167
+ */
168
+ public function getQueryParameters()
169
+ {
170
+ return $this->_queryParams;
171
+ }
172
+
173
+ /**
174
+ * Sets queryParams.
175
+ *
176
+ * Ignores the query variable if its value is empty.
177
+ *
178
+ * @param array $queryParams The queryParams value.
179
+ *
180
+ * @return none
181
+ */
182
+ public function setQueryParameters($queryParams)
183
+ {
184
+ $this->_queryParams = array();
185
+ foreach ($queryParams as $key => $value) {
186
+ $this->addQueryParameter($key, $value);
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Gets uri.
192
+ *
193
+ * @return string
194
+ */
195
+ public function getUri()
196
+ {
197
+ return $this->_uri;
198
+ }
199
+
200
+ /**
201
+ * Sets uri.
202
+ *
203
+ * @param string $uri The uri value.
204
+ *
205
+ * @return none
206
+ */
207
+ public function setUri($uri)
208
+ {
209
+ Validate::isString($uri, 'uri');
210
+
211
+ $this->_uri = $uri;
212
+ }
213
+
214
+ /**
215
+ * Gets path.
216
+ *
217
+ * @return string
218
+ */
219
+ public function getPath()
220
+ {
221
+ return $this->_path;
222
+ }
223
+
224
+ /**
225
+ * Sets path.
226
+ *
227
+ * @param string $path The path value.
228
+ *
229
+ * @return none
230
+ */
231
+ public function setPath($path)
232
+ {
233
+ Validate::isString($path, 'path');
234
+
235
+ $this->_path = $path;
236
+ }
237
+
238
+ /**
239
+ * Gets statusCodes.
240
+ *
241
+ * @return array
242
+ */
243
+ public function getStatusCodes()
244
+ {
245
+ return $this->_statusCodes;
246
+ }
247
+
248
+ /**
249
+ * Sets statusCodes.
250
+ *
251
+ * @param array $statusCodes The statusCodes value.
252
+ *
253
+ * @return none
254
+ */
255
+ public function setStatusCodes($statusCodes)
256
+ {
257
+ $this->_statusCodes = array();
258
+ foreach ($statusCodes as $value) {
259
+ $this->addStatusCode($value);
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Gets body.
265
+ *
266
+ * @return string
267
+ */
268
+ public function getBody()
269
+ {
270
+ return $this->_body;
271
+ }
272
+
273
+ /**
274
+ * Sets body.
275
+ *
276
+ * @param string $body The body value.
277
+ *
278
+ * @return none
279
+ */
280
+ public function setBody($body)
281
+ {
282
+ Validate::isString($body, 'body');
283
+
284
+ $this->_body = $body;
285
+ }
286
+
287
+ /**
288
+ * Adds or sets header pair.
289
+ *
290
+ * @param string $name The HTTP header name.
291
+ * @param string $value The HTTP header value.
292
+ *
293
+ * @return none
294
+ */
295
+ public function addHeader($name, $value)
296
+ {
297
+ Validate::isString($name, 'name');
298
+ Validate::isString($value, 'value');
299
+
300
+ $this->_headers[$name] = $value;
301
+ }
302
+
303
+ /**
304
+ * Adds or sets header pair.
305
+ *
306
+ * Ignores header if it's value satisfies empty().
307
+ *
308
+ * @param string $name The HTTP header name.
309
+ * @param string $value The HTTP header value.
310
+ *
311
+ * @return none
312
+ */
313
+ public function addOptionalHeader($name, $value)
314
+ {
315
+ Validate::isString($name, 'name');
316
+ Validate::isString($value, 'value');
317
+
318
+ if (!empty($value)) {
319
+ $this->_headers[$name] = $value;
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Removes header from the HTTP request headers.
325
+ *
326
+ * @param string $name The HTTP header name.
327
+ *
328
+ * @return none
329
+ */
330
+ public function removeHeader($name)
331
+ {
332
+ Validate::isString($name, 'name');
333
+ Validate::notNullOrEmpty($name, 'name');
334
+
335
+ unset($this->_headers[$name]);
336
+ }
337
+
338
+ /**
339
+ * Adds or sets query parameter pair.
340
+ *
341
+ * @param string $name The URI query parameter name.
342
+ * @param string $value The URI query parameter value.
343
+ *
344
+ * @return none
345
+ */
346
+ public function addQueryParameter($name, $value)
347
+ {
348
+ Validate::isString($name, 'name');
349
+ Validate::isString($value, 'value');
350
+
351
+ $this->_queryParams[$name] = $value;
352
+ }
353
+
354
+ /**
355
+ * Gets HTTP POST parameters.
356
+ *
357
+ * @return array
358
+ */
359
+ public function getPostParameters()
360
+ {
361
+ return $this->_postParameters;
362
+ }
363
+
364
+ /**
365
+ * Sets HTTP POST parameters.
366
+ *
367
+ * @param array $postParameters The HTTP POST parameters.
368
+ *
369
+ * @return none
370
+ */
371
+ public function setPostParameters($postParameters)
372
+ {
373
+ Validate::isArray($postParameters, 'postParameters');
374
+ $this->_postParameters = $postParameters;
375
+ }
376
+
377
+ /**
378
+ * Adds or sets query parameter pair.
379
+ *
380
+ * Ignores query parameter if it's value satisfies empty().
381
+ *
382
+ * @param string $name The URI query parameter name.
383
+ * @param string $value The URI query parameter value.
384
+ *
385
+ * @return none
386
+ */
387
+ public function addOptionalQueryParameter($name, $value)
388
+ {
389
+ Validate::isString($name, 'name');
390
+ Validate::isString($value, 'value');
391
+
392
+ if (!empty($value)) {
393
+ $this->_queryParams[$name] = $value;
394
+ }
395
+ }
396
+
397
+ /**
398
+ * Adds status code to the expected status codes.
399
+ *
400
+ * @param integer $statusCode The expected status code.
401
+ *
402
+ * @return none
403
+ */
404
+ public function addStatusCode($statusCode)
405
+ {
406
+ Validate::isInteger($statusCode, 'statusCode');
407
+
408
+ $this->_statusCodes[] = $statusCode;
409
+ }
410
+
411
+ /**
412
+ * Gets header value.
413
+ *
414
+ * @param string $name The header name.
415
+ *
416
+ * @return mix
417
+ */
418
+ public function getHeader($name)
419
+ {
420
+ return Utilities::tryGetValue($this->_headers, $name);
421
+ }
422
+
423
+ /**
424
+ * Converts the context object to string.
425
+ *
426
+ * @return string
427
+ */
428
+ public function __toString()
429
+ {
430
+ $headers = Resources::EMPTY_STRING;
431
+ $uri = $this->_uri;
432
+
433
+ if ($uri[strlen($uri)-1] != '/')
434
+ {
435
+ $uri = $uri.'/';
436
+ }
437
+
438
+ foreach ($this->_headers as $key => $value) {
439
+ $headers .= "$key: $value\n";
440
+ }
441
+
442
+ $str = "$this->_method $uri$this->_path HTTP/1.1\n$headers\n";
443
+ $str .= "$this->_body";
444
+
445
+ return $str;
446
+ }
447
+ }
448
+
449
+
lib/Azure/MicrosoftAzureStorage/Common/Internal/HttpFormatter.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * LICENSE: The MIT License (the "License")
4
+ * you may not use this file except in compliance with the License.
5
+ * You may obtain a copy of the License at
6
+ * https://github.com/azure/azure-storage-php/LICENSE
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ *
14
+ * PHP version 5
15
+ *
16
+ * @category Microsoft
17
+ * @package MicrosoftAzure\Storage\Common\Internal
18
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
19
+ * @copyright 2016 Microsoft Corporation
20
+ * @license https://github.com/azure/azure-storage-php/LICENSE
21
+ * @link https://github.com/azure/azure-storage-php
22
+ */
23
+
24
+ namespace MicrosoftAzure\Storage\Common\Internal;
25
+
26
+ class HttpFormatter
27
+ {
28
+ /**
29
+ * Convert a http headers array into an uniformed format for further process
30
+ *
31
+ * @param array $headers headers for format
32
+ *
33
+ * @return array
34
+ */
35
+ public static function formatHeaders($headers)
36
+ {
37
+ $result = array();
38
+ foreach ($headers as $key => $value)
39
+ {
40
+ if (is_array($value) && count($value) == 1)
41
+ {
42
+ $result[strtolower($key)] = $value[0];
43
+ }
44
+ else
45
+ {
46
+ $result[strtolower($key)] = $value;
47
+ }
48
+ }
49
+
50
+ return $result;
51
+ }
52
+ }
lib/Azure/MicrosoftAzureStorage/Common/Internal/IServiceFilter.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal;
26
+
27
+ /**
28
+ * ServceFilter is called when the sending the request and after receiving the
29
+ * response.
30
+ *
31
+ * @category Microsoft
32
+ * @package MicrosoftAzure\Storage\Common\Internal
33
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
34
+ * @copyright 2016 Microsoft Corporation
35
+ * @license https://github.com/azure/azure-storage-php/LICENSE
36
+ * @version Release: 0.11.0
37
+ * @link https://github.com/azure/azure-storage-php
38
+ */
39
+ interface IServiceFilter
40
+ {
41
+ /**
42
+ * Processes HTTP request before send.
43
+ *
44
+ * @param mix $request HTTP request object.
45
+ *
46
+ * @return mix processed HTTP request object.
47
+ */
48
+ public function handleRequest($request);
49
+
50
+ /**
51
+ * Processes HTTP response after send.
52
+ *
53
+ * @param mix $request HTTP request object.
54
+ * @param mix $response HTTP response object.
55
+ *
56
+ * @return mix processed HTTP response object.
57
+ */
58
+ public function handleResponse($request, $response);
59
+ }
60
+
61
+
lib/Azure/MicrosoftAzureStorage/Common/Internal/InvalidArgumentTypeException.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal;
26
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
27
+
28
+ /**
29
+ * Exception thrown if an argument type does not match with the expected type.
30
+ *
31
+ * @category Microsoft
32
+ * @package MicrosoftAzure\Storage\Common\Internal
33
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
34
+ * @copyright 2016 Microsoft Corporation
35
+ * @license https://github.com/azure/azure-storage-php/LICENSE
36
+ * @version Release: 0.11.0
37
+ * @link https://github.com/azure/azure-storage-php
38
+ */
39
+ class InvalidArgumentTypeException extends \InvalidArgumentException
40
+ {
41
+ /**
42
+ * Constructor.
43
+ *
44
+ * @param string $validType The valid type that should be provided by the user.
45
+ * @param string $name The parameter name.
46
+ *
47
+ * @return MicrosoftAzure\Storage\Common\Internal\InvalidArgumentTypeException
48
+ */
49
+ public function __construct($validType, $name = null)
50
+ {
51
+ parent::__construct(
52
+ sprintf(Resources::INVALID_PARAM_MSG, $name, $validType)
53
+ );
54
+ }
55
+ }
56
+
57
+
lib/Azure/MicrosoftAzureStorage/Common/Internal/Logger.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal;
26
+
27
+ /**
28
+ * Logger class for debugging purpose.
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Common\Internal
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class Logger
39
+ {
40
+ /**
41
+ * @var string
42
+ */
43
+ private static $_filePath;
44
+
45
+ /**
46
+ * Logs $var to file.
47
+ *
48
+ * @param mix $var The data to log.
49
+ * @param string $tip The help message.
50
+ *
51
+ * @static
52
+ *
53
+ * @return none
54
+ */
55
+ public static function log($var, $tip = Resources::EMPTY_STRING)
56
+ {
57
+ if (!empty($tip)) {
58
+ error_log($tip . "\n", 3, self::$_filePath);
59
+ }
60
+
61
+ if (is_array($var) || is_object($var)) {
62
+ error_log(print_r($var, true), 3, self::$_filePath);
63
+ } else {
64
+ error_log($var . "\n", 3, self::$_filePath);
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Sets file path to use.
70
+ *
71
+ * @param string $filePath The log file path.
72
+ *
73
+ * @static
74
+ *
75
+ * @return none
76
+ */
77
+ public static function setLogFile($filePath)
78
+ {
79
+ self::$_filePath = $filePath;
80
+ }
81
+ }
82
+
83
+
lib/Azure/MicrosoftAzureStorage/Common/Internal/Resources.php ADDED
@@ -0,0 +1,404 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal;
26
+
27
+ /**
28
+ * Project resources.
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Common\Internal
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ class Resources
39
+ {
40
+ // @codingStandardsIgnoreStart
41
+
42
+ // Connection strings
43
+ const USE_DEVELOPMENT_STORAGE_NAME = 'UseDevelopmentStorage';
44
+ const DEVELOPMENT_STORAGE_PROXY_URI_NAME = 'DevelopmentStorageProxyUri';
45
+ const DEFAULT_ENDPOINTS_PROTOCOL_NAME = 'DefaultEndpointsProtocol';
46
+ const ACCOUNT_NAME_NAME = 'AccountName';
47
+ const ACCOUNT_KEY_NAME = 'AccountKey';
48
+ const BLOB_ENDPOINT_NAME = 'BlobEndpoint';
49
+ const QUEUE_ENDPOINT_NAME = 'QueueEndpoint';
50
+ const TABLE_ENDPOINT_NAME = 'TableEndpoint';
51
+ const SHARED_ACCESS_SIGNATURE_NAME = 'SharedAccessSignature';
52
+ const DEV_STORE_NAME = 'devstoreaccount1';
53
+ const DEV_STORE_KEY = 'Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==';
54
+ const BLOB_BASE_DNS_NAME = 'blob.core.windows.net';
55
+ const QUEUE_BASE_DNS_NAME = 'queue.core.windows.net';
56
+ const TABLE_BASE_DNS_NAME = 'table.core.windows.net';
57
+ const DEV_STORE_CONNECTION_STRING = 'BlobEndpoint=127.0.0.1:10000;QueueEndpoint=127.0.0.1:10001;TableEndpoint=127.0.0.1:10002;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==';
58
+ const SUBSCRIPTION_ID_NAME = 'SubscriptionID';
59
+ const CERTIFICATE_PATH_NAME = 'CertificatePath';
60
+
61
+ // Messages
62
+ const INVALID_FUNCTION_NAME = 'The class %s does not have a function named %s.';
63
+ const INVALID_TYPE_MSG = 'The provided variable should be of type: ';
64
+ const INVALID_META_MSG = 'Metadata cannot contain newline characters.';
65
+ const AZURE_ERROR_MSG = "Fail:\nCode: %s\nValue: %s\ndetails (if any): %s.";
66
+ const NOT_IMPLEMENTED_MSG = 'This method is not implemented.';
67
+ const NULL_OR_EMPTY_MSG = "'%s' can't be NULL or empty.";
68
+ const NULL_MSG = "'%s' can't be NULL.";
69
+ const INVALID_URL_MSG = 'Provided URL is invalid.';
70
+ const INVALID_HT_MSG = 'The header type provided is invalid.';
71
+ const INVALID_EDM_MSG = 'The provided EDM type is invalid.';
72
+ const INVALID_PROP_MSG = 'One of the provided properties is not an instance of class Property';
73
+ const INVALID_ENTITY_MSG = 'The provided entity object is invalid.';
74
+ const INVALID_VERSION_MSG = 'Server does not support any known protocol versions.';
75
+ const INVALID_BO_TYPE_MSG = 'Batch operation name is not supported or invalid.';
76
+ const INVALID_BO_PN_MSG = 'Batch operation parameter is not supported.';
77
+ const INVALID_OC_COUNT_MSG = 'Operations and contexts must be of same size.';
78
+ const INVALID_EXC_OBJ_MSG = 'Exception object type should be ServiceException.';
79
+ const NULL_TABLE_KEY_MSG = 'Partition and row keys can\'t be NULL.';
80
+ const BATCH_ENTITY_DEL_MSG = 'The entity was deleted successfully.';
81
+ const INVALID_PROP_VAL_MSG = "'%s' property value must satisfy %s.";
82
+ const INVALID_PARAM_MSG = "The provided variable '%s' should be of type '%s'";
83
+ const INVALID_STRING_LENGTH = "The provided variable '%s' should be of %s characters long";
84
+ const INVALID_BTE_MSG = "The blob block type must exist in %s";
85
+ const INVALID_BLOB_PAT_MSG = 'The provided access type is invalid.';
86
+ const INVALID_SVC_PROP_MSG = 'The provided service properties is invalid.';
87
+ const UNKNOWN_SRILZER_MSG = 'The provided serializer type is unknown';
88
+ const INVALID_CREATE_SERVICE_OPTIONS_MSG = 'Must provide valid location or affinity group.';
89
+ const INVALID_UPDATE_SERVICE_OPTIONS_MSG = 'Must provide either description or label.';
90
+ const INVALID_CONFIG_MSG = 'Config object must be of type Configuration';
91
+ const INVALID_ACH_MSG = 'The provided access condition header is invalid';
92
+ const INVALID_RECEIVE_MODE_MSG = 'The receive message option is in neither RECEIVE_AND_DELETE nor PEEK_LOCK mode.';
93
+ const INVALID_CONFIG_URI = "The provided URI '%s' is invalid. It has to pass the check 'filter_var(<user_uri>, FILTER_VALIDATE_URL)'.";
94
+ const INVALID_CONFIG_VALUE = "The provided config value '%s' does not belong to the valid values subset:\n%s";
95
+ const INVALID_ACCOUNT_KEY_FORMAT = "The provided account key '%s' is not a valid base64 string. It has to pass the check 'base64_decode(<user_account_key>, true)'.";
96
+ const MISSING_CONNECTION_STRING_SETTINGS = "The provided connection string '%s' does not have complete configuration settings.";
97
+ const INVALID_CONNECTION_STRING_SETTING_KEY = "The setting key '%s' is not found in the expected configuration setting keys:\n%s";
98
+ const INVALID_CERTIFICATE_PATH = "The provided certificate path '%s' is invalid.";
99
+ const INSTANCE_TYPE_VALIDATION_MSG = 'The type of %s is %s but is expected to be %s.';
100
+ const MISSING_CONNECTION_STRING_CHAR = "Missing %s character";
101
+ const ERROR_PARSING_STRING = "'%s' at position %d.";
102
+ const INVALID_CONNECTION_STRING = "Argument '%s' is not a valid connection string: '%s'";
103
+ const ERROR_CONNECTION_STRING_MISSING_KEY = 'Missing key name';
104
+ const ERROR_CONNECTION_STRING_EMPTY_KEY = 'Empty key name';
105
+ const ERROR_CONNECTION_STRING_MISSING_CHARACTER = "Missing %s character";
106
+ const ERROR_EMPTY_SETTINGS = 'No keys were found in the connection string';
107
+ const MISSING_LOCK_LOCATION_MSG = 'The lock location of the brokered message is missing.';
108
+ const INVALID_SLOT = "The provided deployment slot '%s' is not valid. Only 'staging' and 'production' are accepted.";
109
+ const INVALID_DEPLOYMENT_LOCATOR_MSG = 'A slot or deployment name must be provided.';
110
+ const INVALID_CHANGE_MODE_MSG = "The change mode must be 'Auto' or 'Manual'. Use Mode class constants for that purpose.";
111
+ const INVALID_DEPLOYMENT_STATUS_MSG = "The change mode must be 'Running' or 'Suspended'. Use DeploymentStatus class constants for that purpose.";
112
+ const ERROR_OAUTH_GET_ACCESS_TOKEN = 'Unable to get oauth access token for endpoint \'%s\', account name \'%s\'';
113
+ const ERROR_OAUTH_SERVICE_MISSING = 'OAuth service missing for account name \'%s\'';
114
+ const ERROR_METHOD_NOT_FOUND = 'Method \'%s\' not found in object class \'%s\'';
115
+ const ERROR_INVALID_DATE_STRING = 'Parameter \'%s\' is not a date formatted string \'%s\'';
116
+ const ERROR_TOO_LARGE_FOR_BLOCK_BLOB = 'Error: Exceeds the uppper limit of the blob.';
117
+ const ERROR_RANGE_NOT_ALIGN_TO_512 = 'Error: Range of the page blob must be align to 512';
118
+ const ERROR_FILE_COULD_NOT_BE_OPENED = 'Error: file with given path could not be opened or created.';
119
+ const ERROR_CONTAINER_NOT_EXIST = 'The specified container does not exist';
120
+ const ERROR_BLOB_NOT_EXIST = 'The specified blob does not exist';
121
+ const INVALID_PARAM_GENERAL = 'The provided parameter \'%s\' is invalid';
122
+ const INVALID_NEGATIVE_PARAM = 'The provided parameter \'%s\' should be positive number.';
123
+
124
+ // HTTP Headers
125
+ const X_MS_HEADER_PREFIX = 'x-ms-';
126
+ const X_MS_META_HEADER_PREFIX = 'x-ms-meta-';
127
+ const X_MS_APPROXIMATE_MESSAGES_COUNT = 'x-ms-approximate-messages-count';
128
+ const X_MS_POPRECEIPT = 'x-ms-popreceipt';
129
+ const X_MS_TIME_NEXT_VISIBLE = 'x-ms-time-next-visible';
130
+ const X_MS_BLOB_PUBLIC_ACCESS = 'x-ms-blob-public-access';
131
+ const X_MS_VERSION = 'x-ms-version';
132
+ const X_MS_DATE = 'x-ms-date';
133
+ const X_MS_BLOB_SEQUENCE_NUMBER = 'x-ms-blob-sequence-number';
134
+ const X_MS_BLOB_SEQUENCE_NUMBER_ACTION = 'x-ms-sequence-number-action';
135
+ const X_MS_BLOB_TYPE = 'x-ms-blob-type';
136
+ const X_MS_BLOB_CONTENT_TYPE = 'x-ms-blob-content-type';
137
+ const X_MS_BLOB_CONTENT_ENCODING = 'x-ms-blob-content-encoding';
138
+ const X_MS_BLOB_CONTENT_LANGUAGE = 'x-ms-blob-content-language';
139
+ const X_MS_BLOB_CONTENT_MD5 = 'x-ms-blob-content-md5';
140
+ const X_MS_BLOB_CACHE_CONTROL = 'x-ms-blob-cache-control';
141
+ const X_MS_BLOB_CONTENT_LENGTH = 'x-ms-blob-content-length';
142
+ const X_MS_COPY_SOURCE = 'x-ms-copy-source';
143
+ const X_MS_RANGE = 'x-ms-range';
144
+ const X_MS_RANGE_GET_CONTENT_MD5 = 'x-ms-range-get-content-md5';
145
+ const X_MS_LEASE_DURATION = 'x-ms-lease-duration';
146
+ const X_MS_LEASE_ID = 'x-ms-lease-id';
147
+ const X_MS_LEASE_TIME = 'x-ms-lease-time';
148
+ const X_MS_LEASE_STATUS = 'x-ms-lease-status';
149
+ const X_MS_LEASE_ACTION = 'x-ms-lease-action';
150
+ const X_MS_DELETE_SNAPSHOTS = 'x-ms-delete-snapshots';
151
+ const X_MS_PAGE_WRITE = 'x-ms-page-write';
152
+ const X_MS_SNAPSHOT = 'x-ms-snapshot';
153
+ const X_MS_SOURCE_IF_MODIFIED_SINCE = 'x-ms-source-if-modified-since';
154
+ const X_MS_SOURCE_IF_UNMODIFIED_SINCE = 'x-ms-source-if-unmodified-since';
155
+ const X_MS_SOURCE_IF_MATCH = 'x-ms-source-if-match';
156
+ const X_MS_SOURCE_IF_NONE_MATCH = 'x-ms-source-if-none-match';
157
+ const X_MS_SOURCE_LEASE_ID = 'x-ms-source-lease-id';
158
+ const X_MS_CONTINUATION_NEXTTABLENAME = 'x-ms-continuation-nexttablename';
159
+ const X_MS_CONTINUATION_NEXTPARTITIONKEY = 'x-ms-continuation-nextpartitionkey';
160
+ const X_MS_CONTINUATION_NEXTROWKEY = 'x-ms-continuation-nextrowkey';
161
+ const X_MS_REQUEST_ID = 'x-ms-request-id';
162
+ const ETAG = 'etag';
163
+ const LAST_MODIFIED = 'last-modified';
164
+ const DATE = 'date';
165
+ const AUTHENTICATION = 'authorization';
166
+ const WRAP_AUTHORIZATION = 'WRAP access_token="%s"';
167
+ const CONTENT_ENCODING = 'content-encoding';
168
+ const CONTENT_LANGUAGE = 'content-language';
169
+ const CONTENT_LENGTH = 'content-length';
170
+ const CONTENT_LENGTH_NO_SPACE = 'contentlength';
171
+ const CONTENT_MD5 = 'content-md5';
172
+ const CONTENT_TYPE = 'content-type';
173
+ const CONTENT_ID = 'content-id';
174
+ const CONTENT_RANGE = 'content-range';
175
+ const CACHE_CONTROL = 'cache-control';
176
+ const IF_MODIFIED_SINCE = 'if-modified-since';
177
+ const IF_MATCH = 'if-match';
178
+ const IF_NONE_MATCH = 'if-none-match';
179
+ const IF_UNMODIFIED_SINCE = 'if-unmodified-since';
180
+ const RANGE = 'range';
181
+ const DATA_SERVICE_VERSION = 'dataserviceversion';
182
+ const MAX_DATA_SERVICE_VERSION = 'maxdataserviceversion';
183
+ const ACCEPT_HEADER = 'accept';
184
+ const ACCEPT_CHARSET = 'accept-charset';
185
+ const USER_AGENT = 'User-Agent';
186
+
187
+ // Type
188
+ const QUEUE_TYPE_NAME = 'IQueue';
189
+ const BLOB_TYPE_NAME = 'IBlob';
190
+ const TABLE_TYPE_NAME = 'ITable';
191
+
192
+ // WRAP
193
+ const WRAP_ACCESS_TOKEN = 'wrap_access_token';
194
+ const WRAP_ACCESS_TOKEN_EXPIRES_IN = 'wrap_access_token_expires_in';
195
+ const WRAP_NAME = 'wrap_name';
196
+ const WRAP_PASSWORD = 'wrap_password';
197
+ const WRAP_SCOPE = 'wrap_scope';
198
+
199
+ // HTTP Methods
200
+ const HTTP_GET = 'GET';
201
+ const HTTP_PUT = 'PUT';
202
+ const HTTP_POST = 'POST';
203
+ const HTTP_HEAD = 'HEAD';
204
+ const HTTP_DELETE = 'DELETE';
205
+ const HTTP_MERGE = 'MERGE';
206
+
207
+ // Misc
208
+ const EMPTY_STRING = '';
209
+ const SEPARATOR = ',';
210
+ const AZURE_DATE_FORMAT = 'D, d M Y H:i:s T';
211
+ const TIMESTAMP_FORMAT = 'Y-m-d H:i:s';
212
+ const EMULATED = 'EMULATED';
213
+ const EMULATOR_BLOB_URI = '127.0.0.1:10000';
214
+ const EMULATOR_QUEUE_URI = '127.0.0.1:10001';
215
+ const EMULATOR_TABLE_URI = '127.0.0.1:10002';
216
+ const ASTERISK = '*';
217
+ const SERVICE_MANAGEMENT_URL = 'https://management.core.windows.net';
218
+ const HTTP_SCHEME = 'http';
219
+ const HTTPS_SCHEME = 'https';
220
+ const SETTING_NAME = 'SettingName';
221
+ const SETTING_CONSTRAINT = 'SettingConstraint';
222
+ const DEV_STORE_URI = 'http://127.0.0.1';
223
+ const SERVICE_URI_FORMAT = "%s://%s.%s";
224
+ const WRAP_ENDPOINT_URI_FORMAT = "https://%s-sb.accesscontrol.windows.net/WRAPv0.9";
225
+ const MB_IN_BYTES_4 = 4194304;
226
+ const MB_IN_BYTES_32 = 33554432;
227
+ const MB_IN_BYTES_64 = 67108864;
228
+ const MAX_BLOB_BLOCKS = 50000;
229
+
230
+ // Xml Namespaces
231
+ const WA_XML_NAMESPACE = 'http://schemas.microsoft.com/windowsazure';
232
+ const ATOM_XML_NAMESPACE = 'http://www.w3.org/2005/Atom';
233
+ const DS_XML_NAMESPACE = 'http://schemas.microsoft.com/ado/2007/08/dataservices';
234
+ const DSM_XML_NAMESPACE = 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata';
235
+ const XSI_XML_NAMESPACE = 'http://www.w3.org/2001/XMLSchema-instance';
236
+ const NUMBER_OF_CONCURRENCY = 25;//Guzzle's default value
237
+ const DEFAULT_NUMBER_OF_RETRIES = 3;
238
+ const DEAFULT_RETRY_INTERVAL = 1000;//Milliseconds
239
+
240
+ // Header values
241
+ const SDK_VERSION = '0.11.0';
242
+ const STORAGE_API_LATEST_VERSION = '2015-04-05';
243
+ const DATA_SERVICE_VERSION_VALUE = '1.0;NetFx';
244
+ const MAX_DATA_SERVICE_VERSION_VALUE = '2.0;NetFx';
245
+ const ACCEPT_HEADER_VALUE = 'application/atom+xml,application/xml';
246
+ const ATOM_ENTRY_CONTENT_TYPE = 'application/atom+xml;type=entry;charset=utf-8';
247
+ const ATOM_FEED_CONTENT_TYPE = 'application/atom+xml;type=feed;charset=utf-8';
248
+ const ACCEPT_CHARSET_VALUE = 'utf-8';
249
+ const INT32_MAX = 2147483647;
250
+
251
+ // Query parameter names
252
+ const QP_PREFIX = 'Prefix';
253
+ const QP_MAX_RESULTS = 'MaxResults';
254
+ const QP_METADATA = 'Metadata';
255
+ const QP_MARKER = 'Marker';
256
+ const QP_NEXT_MARKER = 'NextMarker';
257
+ const QP_COMP = 'comp';
258
+ const QP_VISIBILITY_TIMEOUT = 'visibilitytimeout';
259
+ const QP_POPRECEIPT = 'popreceipt';
260
+ const QP_NUM_OF_MESSAGES = 'numofmessages';
261
+ const QP_PEEK_ONLY = 'peekonly';
262
+ const QP_MESSAGE_TTL = 'messagettl';
263
+ const QP_INCLUDE = 'include';
264
+ const QP_TIMEOUT = 'timeout';
265
+ const QP_DELIMITER = 'Delimiter';
266
+ const QP_REST_TYPE = 'restype';
267
+ const QP_SNAPSHOT = 'snapshot';
268
+ const QP_BLOCKID = 'blockid';
269
+ const QP_BLOCK_LIST_TYPE = 'blocklisttype';
270
+ const QP_SELECT = '$select';
271
+ const QP_TOP = '$top';
272
+ const QP_SKIP = '$skip';
273
+ const QP_FILTER = '$filter';
274
+ const QP_NEXT_TABLE_NAME = 'NextTableName';
275
+ const QP_NEXT_PK = 'NextPartitionKey';
276
+ const QP_NEXT_RK = 'NextRowKey';
277
+ const QP_ACTION = 'action';
278
+ const QP_EMBED_DETAIL = 'embed-detail';
279
+
280
+ // Query parameter values
281
+ const QPV_REGENERATE = 'regenerate';
282
+ const QPV_CONFIG = 'config';
283
+ const QPV_STATUS = 'status';
284
+ const QPV_UPGRADE = 'upgrade';
285
+ const QPV_WALK_UPGRADE_DOMAIN = 'walkupgradedomain';
286
+ const QPV_REBOOT = 'reboot';
287
+ const QPV_REIMAGE = 'reimage';
288
+ const QPV_ROLLBACK = 'rollback';
289
+
290
+ // Request body content types
291
+ const URL_ENCODED_CONTENT_TYPE = 'application/x-www-form-urlencoded';
292
+ const XML_CONTENT_TYPE = 'application/xml';
293
+ const JSON_CONTENT_TYPE = 'application/json';
294
+ const BINARY_FILE_TYPE = 'application/octet-stream';
295
+ const XML_ATOM_CONTENT_TYPE = 'application/atom+xml';
296
+ const HTTP_TYPE = 'application/http';
297
+ const MULTIPART_MIXED_TYPE = 'multipart/mixed';
298
+
299
+ // Common used XML tags
300
+ const XTAG_ATTRIBUTES = '@attributes';
301
+ const XTAG_NAMESPACE = '@namespace';
302
+ const XTAG_LABEL = 'Label';
303
+ const XTAG_NAME = 'Name';
304
+ const XTAG_DESCRIPTION = 'Description';
305
+ const XTAG_LOCATION = 'Location';
306
+ const XTAG_AFFINITY_GROUP = 'AffinityGroup';
307
+ const XTAG_HOSTED_SERVICES = 'HostedServices';
308
+ const XTAG_STORAGE_SERVICES = 'StorageServices';
309
+ const XTAG_STORAGE_SERVICE = 'StorageService';
310
+ const XTAG_DISPLAY_NAME = 'DisplayName';
311
+ const XTAG_SERVICE_NAME = 'ServiceName';
312
+ const XTAG_URL = 'Url';
313
+ const XTAG_ID = 'ID';
314
+ const XTAG_STATUS = 'Status';
315
+ const XTAG_HTTP_STATUS_CODE = 'HttpStatusCode';
316
+ const XTAG_CODE = 'Code';
317
+ const XTAG_MESSAGE = 'Message';
318
+ const XTAG_STORAGE_SERVICE_PROPERTIES = 'StorageServiceProperties';
319
+ const XTAG_SERVICE_ENDPOINT = 'ServiceEndpoint';
320
+ const XTAG_ENDPOINT = 'Endpoint';
321
+ const XTAG_ENDPOINTS = 'Endpoints';
322
+ const XTAG_PRIMARY = 'Primary';
323
+ const XTAG_SECONDARY = 'Secondary';
324
+ const XTAG_KEY_TYPE = 'KeyType';
325
+ const XTAG_STORAGE_SERVICE_KEYS = 'StorageServiceKeys';
326
+ const XTAG_ERROR = 'Error';
327
+ const XTAG_HOSTED_SERVICE = 'HostedService';
328
+ const XTAG_HOSTED_SERVICE_PROPERTIES = 'HostedServiceProperties';
329
+ const XTAG_CREATE_HOSTED_SERVICE = 'CreateHostedService';
330
+ const XTAG_CREATE_STORAGE_SERVICE_INPUT = 'CreateStorageServiceInput';
331
+ const XTAG_UPDATE_STORAGE_SERVICE_INPUT = 'UpdateStorageServiceInput';
332
+ const XTAG_CREATE_AFFINITY_GROUP = 'CreateAffinityGroup';
333
+ const XTAG_UPDATE_AFFINITY_GROUP = 'UpdateAffinityGroup';
334
+ const XTAG_UPDATE_HOSTED_SERVICE = 'UpdateHostedService';
335
+ const XTAG_PACKAGE_URL = 'PackageUrl';
336
+ const XTAG_CONFIGURATION = 'Configuration';
337
+ const XTAG_START_DEPLOYMENT = 'StartDeployment';
338
+ const XTAG_TREAT_WARNINGS_AS_ERROR = 'TreatWarningsAsError';
339
+ const XTAG_CREATE_DEPLOYMENT = 'CreateDeployment';
340
+ const XTAG_DEPLOYMENT_SLOT = 'DeploymentSlot';
341
+ const XTAG_PRIVATE_ID = 'PrivateID';
342
+ const XTAG_ROLE_INSTANCE_LIST = 'RoleInstanceList';
343
+ const XTAG_UPGRADE_DOMAIN_COUNT = 'UpgradeDomainCount';
344
+ const XTAG_ROLE_LIST = 'RoleList';
345
+ const XTAG_SDK_VERSION = 'SdkVersion';
346
+ const XTAG_INPUT_ENDPOINT_LIST = 'InputEndpointList';
347
+ const XTAG_LOCKED = 'Locked';
348
+ const XTAG_ROLLBACK_ALLOWED = 'RollbackAllowed';
349
+ const XTAG_UPGRADE_STATUS = 'UpgradeStatus';
350
+ const XTAG_UPGRADE_TYPE = 'UpgradeType';
351
+ const XTAG_CURRENT_UPGRADE_DOMAIN_STATE = 'CurrentUpgradeDomainState';
352
+ const XTAG_CURRENT_UPGRADE_DOMAIN = 'CurrentUpgradeDomain';
353
+ const XTAG_ROLE_NAME = 'RoleName';
354
+ const XTAG_INSTANCE_NAME = 'InstanceName';
355
+ const XTAG_INSTANCE_STATUS = 'InstanceStatus';
356
+ const XTAG_INSTANCE_UPGRADE_DOMAIN = 'InstanceUpgradeDomain';
357
+ const XTAG_INSTANCE_FAULT_DOMAIN = 'InstanceFaultDomain';
358
+ const XTAG_INSTANCE_SIZE = 'InstanceSize';
359
+ const XTAG_INSTANCE_STATE_DETAILS = 'InstanceStateDetails';
360
+ const XTAG_INSTANCE_ERROR_CODE = 'InstanceErrorCode';
361
+ const XTAG_OS_VERSION = 'OsVersion';
362
+ const XTAG_ROLE_INSTANCE = 'RoleInstance';
363
+ const XTAG_ROLE = 'Role';
364
+ const XTAG_INPUT_ENDPOINT = 'InputEndpoint';
365
+ const XTAG_VIP = 'Vip';
366
+ const XTAG_PORT = 'Port';
367
+ const XTAG_DEPLOYMENT = 'Deployment';
368
+ const XTAG_DEPLOYMENTS = 'Deployments';
369
+ const XTAG_REGENERATE_KEYS = 'RegenerateKeys';
370
+ const XTAG_SWAP = 'Swap';
371
+ const XTAG_PRODUCTION = 'Production';
372
+ const XTAG_SOURCE_DEPLOYMENT = 'SourceDeployment';
373
+ const XTAG_CHANGE_CONFIGURATION = 'ChangeConfiguration';
374
+ const XTAG_MODE = 'Mode';
375
+ const XTAG_UPDATE_DEPLOYMENT_STATUS = 'UpdateDeploymentStatus';
376
+ const XTAG_ROLE_TO_UPGRADE = 'RoleToUpgrade';
377
+ const XTAG_FORCE = 'Force';
378
+ const XTAG_UPGRADE_DEPLOYMENT = 'UpgradeDeployment';
379
+ const XTAG_UPGRADE_DOMAIN = 'UpgradeDomain';
380
+ const XTAG_WALK_UPGRADE_DOMAIN = 'WalkUpgradeDomain';
381
+ const XTAG_ROLLBACK_UPDATE_OR_UPGRADE = 'RollbackUpdateOrUpgrade';
382
+ const XTAG_CONTAINER_NAME = 'ContainerName';
383
+ const XTAG_ACCOUNT_NAME = 'AccountName';
384
+
385
+ // PHP URL Keys
386
+ const PHP_URL_SCHEME = 'scheme';
387
+ const PHP_URL_HOST = 'host';
388
+ const PHP_URL_PORT = 'port';
389
+ const PHP_URL_USER = 'user';
390
+ const PHP_URL_PASS = 'pass';
391
+ const PHP_URL_PATH = 'path';
392
+ const PHP_URL_QUERY = 'query';
393
+ const PHP_URL_FRAGMENT = 'fragment';
394
+
395
+ // Status Codes
396
+ const STATUS_OK = 200;
397
+ const STATUS_CREATED = 201;
398
+ const STATUS_ACCEPTED = 202;
399
+ const STATUS_NO_CONTENT = 204;
400
+ const STATUS_PARTIAL_CONTENT = 206;
401
+ const STATUS_MOVED_PERMANENTLY = 301;
402
+
403
+ // @codingStandardsIgnoreEnd
404
+ }
lib/Azure/MicrosoftAzureStorage/Common/Internal/RestProxy.php ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
28
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
29
+
30
+ /**
31
+ * Base class for all REST proxies.
32
+ *
33
+ * @category Microsoft
34
+ * @package MicrosoftAzure\Storage\Common\Internal
35
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
36
+ * @copyright 2016 Microsoft Corporation
37
+ * @license https://github.com/azure/azure-storage-php/LICENSE
38
+ * @version Release: 0.11.0
39
+ * @link https://github.com/azure/azure-storage-php
40
+ */
41
+ class RestProxy
42
+ {
43
+ /**
44
+ * @var array
45
+ */
46
+ private $_filters;
47
+
48
+ /**
49
+ * @var MicrosoftAzure\Storage\Common\Internal\Serialization\ISerializer
50
+ */
51
+ protected $dataSerializer;
52
+
53
+ /**
54
+ * @var string
55
+ */
56
+ private $_uri;
57
+
58
+ /**
59
+ * Initializes new RestProxy object.
60
+ *
61
+ * @param ISerializer $dataSerializer The data serializer.
62
+ * @param string $uri The uri of the service.
63
+ */
64
+ public function __construct($dataSerializer, $uri)
65
+ {
66
+ $this->_filters = array();
67
+ $this->dataSerializer = $dataSerializer;
68
+ $this->_uri = $uri;
69
+ }
70
+
71
+ /**
72
+ * Gets HTTP filters that will process each request.
73
+ *
74
+ * @return array
75
+ */
76
+ public function getFilters()
77
+ {
78
+ return $this->_filters;
79
+ }
80
+
81
+ /**
82
+ * Gets the Uri of the service.
83
+ *
84
+ * @return string
85
+ */
86
+ public function getUri()
87
+ {
88
+ return $this->_uri;
89
+ }
90
+
91
+ /**
92
+ * Sets the Uri of the service.
93
+ *
94
+ * @param string $uri The URI of the request.
95
+ *
96
+ * @return none
97
+ */
98
+ public function setUri($uri)
99
+ {
100
+ $this->_uri = $uri;
101
+ }
102
+
103
+ /**
104
+ * Adds new filter to new service rest proxy object and returns that object back.
105
+ *
106
+ * @param MicrosoftAzure\Storage\Common\Internal\IServiceFilter $filter Filter to add for
107
+ * the pipeline.
108
+ *
109
+ * @return RestProxy.
110
+ */
111
+ public function withFilter($filter)
112
+ {
113
+ $serviceProxyWithFilter = clone $this;
114
+ $serviceProxyWithFilter->_filters[] = $filter;
115
+
116
+ return $serviceProxyWithFilter;
117
+ }
118
+
119
+ /**
120
+ * Adds optional query parameter.
121
+ *
122
+ * Doesn't add the value if it satisfies empty().
123
+ *
124
+ * @param array &$queryParameters The query parameters.
125
+ * @param string $key The query variable name.
126
+ * @param string $value The query variable value.
127
+ *
128
+ * @return none
129
+ */
130
+ protected function addOptionalQueryParam(&$queryParameters, $key, $value)
131
+ {
132
+ Validate::isArray($queryParameters, 'queryParameters');
133
+ Validate::isString($key, 'key');
134
+ Validate::isString($value, 'value');
135
+
136
+ if (!is_null($value) && Resources::EMPTY_STRING !== $value) {
137
+ $queryParameters[$key] = $value;
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Adds optional header.
143
+ *
144
+ * Doesn't add the value if it satisfies empty().
145
+ *
146
+ * @param array &$headers The HTTP header parameters.
147
+ * @param string $key The HTTP header name.
148
+ * @param string $value The HTTP header value.
149
+ *
150
+ * @return none
151
+ */
152
+ protected function addOptionalHeader(&$headers, $key, $value)
153
+ {
154
+ Validate::isArray($headers, 'headers');
155
+ Validate::isString($key, 'key');
156
+ Validate::isString($value, 'value');
157
+
158
+ if (!is_null($value) && Resources::EMPTY_STRING !== $value) {
159
+ $headers[$key] = $value;
160
+ }
161
+ }
162
+ }
lib/Azure/MicrosoftAzureStorage/Common/Internal/RetryMiddlewareFactory.php ADDED
@@ -0,0 +1,234 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal;
26
+
27
+ use MicrosoftAzure\Storage\Common\Internal\Resources;
28
+ use MicrosoftAzure\Storage\Common\Internal\Validate;
29
+ use GuzzleHttp\Middleware;
30
+
31
+ /**
32
+ * This class provides static functions that creates retry handlers for Guzzle
33
+ * HTTP clients to handle retry policy.
34
+ *
35
+ * @category Microsoft
36
+ * @package MicrosoftAzure\Storage\Common\Internal
37
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
38
+ * @copyright 2016 Microsoft Corporation
39
+ * @license https://github.com/azure/azure-storage-php/LICENSE
40
+ * @version Release: 0.11.0
41
+ * @link https://github.com/azure/azure-storage-php
42
+ */
43
+ class RetryMiddlewareFactory
44
+ {
45
+ const LINEAR_INTERVAL_ACCUMULATION = 'Linear';
46
+ const EXPONENTIAL_INTERVAL_ACCUMULATION = 'Exponential';
47
+ const GENERAL_RETRY_TYPE = 'General';
48
+ const APPEND_BLOB_RETRY_TYPE = 'Append Blob Retry';
49
+
50
+ /**
51
+ * Create the retry handler for the Guzzle client, according to the given
52
+ * attributes.
53
+ *
54
+ * @param string $type The type that controls the logic of
55
+ * the decider of the retry handler.
56
+ * @param int $numberOfRetries The maximum number of retries.
57
+ * @param int $interval The minimum interval between each retry
58
+ * @param string $accumulationMethod If the interval increases linearly or
59
+ * exponentially.
60
+ *
61
+ * @return RetryMiddleware A RetryMiddleware object that contains
62
+ * the logic of how the request should be
63
+ * handled after a response.
64
+ */
65
+ public static function create(
66
+ $type = self::GENERAL_RETRY_TYPE,
67
+ $numberOfRetries = Resources::DEFAULT_NUMBER_OF_RETRIES,
68
+ $interval = Resources::DEAFULT_RETRY_INTERVAL,
69
+ $accumulationMethod = self::LINEAR_INTERVAL_ACCUMULATION
70
+ ) {
71
+ //Validate the input parameters
72
+ //type
73
+ Validate::isTrue(
74
+ $type == self::GENERAL_RETRY_TYPE ||
75
+ $type == self::APPEND_BLOB_RETRY_TYPE,
76
+ sprintf(
77
+ Resources::INVALID_PARAM_GENERAL,
78
+ 'type'
79
+ )
80
+ );
81
+ //numberOfRetries
82
+ Validate::isTrue(
83
+ $numberOfRetries > 0,
84
+ sprintf(
85
+ Resources::INVALID_NEGATIVE_PARAM,
86
+ 'numberOfRetries'
87
+ )
88
+ );
89
+ //interval
90
+ Validate::isTrue(
91
+ $interval > 0,
92
+ sprintf(
93
+ Resources::INVALID_NEGATIVE_PARAM,
94
+ 'interval'
95
+ )
96
+ );
97
+ //accumulationMethod
98
+ Validate::isTrue(
99
+ $accumulationMethod == self::LINEAR_INTERVAL_ACCUMULATION ||
100
+ $accumulationMethod == self::EXPONENTIAL_INTERVAL_ACCUMULATION,
101
+ sprintf(
102
+ Resources::INVALID_PARAM_GENERAL,
103
+ 'accumulationMethod'
104
+ )
105
+ );
106
+
107
+ //Get the interval calculator according to the type of the
108
+ //accumulation method.
109
+ $intervalCalculator =
110
+ $accumulationMethod == self::LINEAR_INTERVAL_ACCUMULATION ?
111
+ self::createLinearDelayCalculator($interval) :
112
+ self::createExponentialDelayCalculator($interval);
113
+
114
+ //Get the retry decider according to the type of the retry and
115
+ //the number of retries.
116
+ $retryDecider = self::createRetryDecider($type, $numberOfRetries);
117
+
118
+ //construct the retry middle ware.
119
+ return Middleware::retry($retryDecider, $intervalCalculator);
120
+ }
121
+
122
+ /**
123
+ * Create the retry decider for the retry handler. It will return a callable
124
+ * that accepts the number of retries, the request, the response and the
125
+ * exception, and return the decision for a retry.
126
+ *
127
+ * @param string $type The type of the retry handler.
128
+ *
129
+ * @return callable The callable that will return if the request should
130
+ * be retried.
131
+ */
132
+ protected static function createRetryDecider($type, $maxRetries)
133
+ {
134
+ return function (
135
+ $retries,
136
+ $request,
137
+ $response = null,
138
+ $exception = null
139
+ ) use (
140
+ $type,
141
+ $maxRetries
142
+ ) {
143
+ //Exceeds the retry limit. No retry.
144
+ if ($retries >= $maxRetries) {
145
+ return false;
146
+ }
147
+
148
+ //Not retriable error, won't retry.
149
+ if (!$response) {
150
+ return false;
151
+ } else {
152
+ if ($type == self::GENERAL_RETRY_TYPE) {
153
+ return self::generalRetryDecider($response->getStatusCode());
154
+ } else {
155
+ return self::appendBlobRetryDecider($response->getStatusCode());
156
+ }
157
+ }
158
+
159
+ return true;
160
+ };
161
+ }
162
+
163
+ /**
164
+ * Decide if the given status code indicate the request should be retried.
165
+ *
166
+ * @param int $statusCode status code of the previous request.
167
+ *
168
+ * @return bool true if the request should be retried.
169
+ */
170
+ protected static function generalRetryDecider($statusCode)
171
+ {
172
+ $retry = false;
173
+ if ($statusCode == 408) {
174
+ $retry = true;
175
+ } elseif ($statusCode >= 500) {
176
+ if ($statusCode != 501 && $statusCode != 505) {
177
+ $retry = true;
178
+ }
179
+ }
180
+ return $retry;
181
+ }
182
+
183
+ /**
184
+ * Decide if the given status code indicate the request should be retried.
185
+ * This is for append blob.
186
+ *
187
+ * @param int $statusCode status code of the previous request.
188
+ *
189
+ * @return bool true if the request should be retried.
190
+ */
191
+ protected static function appendBlobRetryDecider($statusCode)
192
+ {
193
+ //The retry logic is different for append blob.
194
+ //First it will need to record the former status code if it is
195
+ //server error. Then if the following request is 412 then it
196
+ //needs to be retried. Currently this is not implemented so will
197
+ //only adapt to the general retry decider.
198
+ //TODO: add logic for append blob's retry when implemented.
199
+ $retry = self::generalRetryDecider($statusCode);
200
+ return $retry;
201
+ }
202
+
203
+ /**
204
+ * Create the delay calculator that increases the interval linearly
205
+ * according to the number of retries.
206
+ *
207
+ * @param int $interval the minimum interval of the retry.
208
+ *
209
+ * @return callable a calculator that will return the interval
210
+ * according to the number of retries.
211
+ */
212
+ protected static function createLinearDelayCalculator($interval)
213
+ {
214
+ return function ($retries) use ($interval) {
215
+ return $retries * $interval;
216
+ };
217
+ }
218
+
219
+ /**
220
+ * Create the delay calculator that increases the interval exponentially
221
+ * according to the number of retries.
222
+ *
223
+ * @param int $interval the minimum interval of the retry.
224
+ *
225
+ * @return callable a calculator that will return the interval
226
+ * according to the number of retries.
227
+ */
228
+ protected static function createExponentialDelayCalculator($interval)
229
+ {
230
+ return function ($retries) use ($interval) {
231
+ return $interval * ((int)\pow(2, $retries));
232
+ };
233
+ }
234
+ }
lib/Azure/MicrosoftAzureStorage/Common/Internal/Serialization/ISerializer.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * LICENSE: The MIT License (the "License")
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://github.com/azure/azure-storage-php/LICENSE
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ *
15
+ * PHP version 5
16
+ *
17
+ * @category Microsoft
18
+ * @package MicrosoftAzure\Storage\Common\Internal\Serialization
19
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
20
+ * @copyright 2016 Microsoft Corporation
21
+ * @license https://github.com/azure/azure-storage-php/LICENSE
22
+ * @link https://github.com/azure/azure-storage-php
23
+ */
24
+
25
+ namespace MicrosoftAzure\Storage\Common\Internal\Serialization;
26
+
27
+ /**
28
+ * The serialization interface.
29
+ *
30
+ * @category Microsoft
31
+ * @package MicrosoftAzure\Storage\Common\Internal\Serialization
32
+ * @author Azure Storage PHP SDK <dmsh@microsoft.com>
33
+ * @copyright 2016 Microsoft Corporation
34
+ * @license https://github.com/azure/azure-storage-php/LICENSE
35
+ * @version Release: 0.11.0
36
+ * @link https://github.com/azure/azure-storage-php
37
+ */
38
+ interface ISerializer
39
+ {
40
+
41
+ /**
42
+ * Serialize an object into a XML.
43
+ *
44
+ * @param Object $targetObject The target object to be serialized.
45
+ * @param string $rootName The name of the root.
46
+ *
47
+ * @return string
48
+ */
49
+ public static function objectSerialize($targetObject, $rootName);
50
+
51
+ /**
52
+ * Serializes given array. The array indices must be string to use them as
53
+ * as element name.
54
+ *
55
+ * @param array $array The object to serialize represented in array.
56
+ * @param array $properties The used properties in the serialization process.
57
+ *
58
+ * @return string
59
+ */
60
+ public function serialize($array, $properties = null);
61
+
62
+
63
+ /**
64
+ * Unserializes given serialized string.
65
+ *
66
+ * @param string $serialized The serialized object in string representation.
67
+ *
68
+