bixbite 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. data/LICENSE +20 -0
  2. data/README.markdown +49 -0
  3. data/VERSION +1 -0
  4. data/bin/bixbite +73 -0
  5. data/lib/bixbite.rb +13 -0
  6. data/lib/bixbite/command.rb +14 -0
  7. data/lib/bixbite/create.rb +76 -0
  8. data/template/Rakefile +25 -0
  9. data/template/assets/bixbite/Rakefile.rb +297 -0
  10. data/template/assets/naturaldocs/NaturalDocs/Config/Languages.txt +286 -0
  11. data/template/assets/naturaldocs/NaturalDocs/Config/Topics.txt +382 -0
  12. data/template/assets/naturaldocs/NaturalDocs/Help/customizinglanguages.html +52 -0
  13. data/template/assets/naturaldocs/NaturalDocs/Help/customizingtopics.html +74 -0
  14. data/template/assets/naturaldocs/NaturalDocs/Help/documenting.html +58 -0
  15. data/template/assets/naturaldocs/NaturalDocs/Help/documenting/reference.html +146 -0
  16. data/template/assets/naturaldocs/NaturalDocs/Help/documenting/walkthrough.html +180 -0
  17. data/template/assets/naturaldocs/NaturalDocs/Help/example/Default.css +528 -0
  18. data/template/assets/naturaldocs/NaturalDocs/Help/example/NaturalDocs.js +204 -0
  19. data/template/assets/naturaldocs/NaturalDocs/Help/examples.css +90 -0
  20. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/background.png +0 -0
  21. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/leftside.png +0 -0
  22. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/logo.png +0 -0
  23. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overbody.png +0 -0
  24. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overbodybg.png +0 -0
  25. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overleftmargin.png +0 -0
  26. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overmenu.png +0 -0
  27. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overmenubg.png +0 -0
  28. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/rightside.png +0 -0
  29. data/template/assets/naturaldocs/NaturalDocs/Help/images/logo.gif +0 -0
  30. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/about.png +0 -0
  31. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/background.png +0 -0
  32. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/bottomleft.png +0 -0
  33. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/bottomright.png +0 -0
  34. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/community.png +0 -0
  35. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/customizing.png +0 -0
  36. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/using.png +0 -0
  37. data/template/assets/naturaldocs/NaturalDocs/Help/index.html +9 -0
  38. data/template/assets/naturaldocs/NaturalDocs/Help/javascript/BrowserStyles.js +77 -0
  39. data/template/assets/naturaldocs/NaturalDocs/Help/javascript/PNGHandling.js +72 -0
  40. data/template/assets/naturaldocs/NaturalDocs/Help/keywords.html +38 -0
  41. data/template/assets/naturaldocs/NaturalDocs/Help/languages.html +32 -0
  42. data/template/assets/naturaldocs/NaturalDocs/Help/menu.html +79 -0
  43. data/template/assets/naturaldocs/NaturalDocs/Help/output.html +84 -0
  44. data/template/assets/naturaldocs/NaturalDocs/Help/running.html +40 -0
  45. data/template/assets/naturaldocs/NaturalDocs/Help/styles.css +290 -0
  46. data/template/assets/naturaldocs/NaturalDocs/Help/styles.html +52 -0
  47. data/template/assets/naturaldocs/NaturalDocs/Help/troubleshooting.html +18 -0
  48. data/template/assets/naturaldocs/NaturalDocs/Info/CSSGuide.txt +947 -0
  49. data/template/assets/naturaldocs/NaturalDocs/Info/File Parsing.txt +83 -0
  50. data/template/assets/naturaldocs/NaturalDocs/Info/HTMLTestCases.pm +269 -0
  51. data/template/assets/naturaldocs/NaturalDocs/Info/Languages.txt +107 -0
  52. data/template/assets/naturaldocs/NaturalDocs/Info/NDMarkup.txt +91 -0
  53. data/template/assets/naturaldocs/NaturalDocs/Info/Symbol Management.txt +59 -0
  54. data/template/assets/naturaldocs/NaturalDocs/Info/images/Logo.png +0 -0
  55. data/template/assets/naturaldocs/NaturalDocs/JavaScript/NaturalDocs.js +836 -0
  56. data/template/assets/naturaldocs/NaturalDocs/License-GPL.txt +341 -0
  57. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/BinaryFile.pm +294 -0
  58. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder.pm +280 -0
  59. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/Base.pm +348 -0
  60. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/FramedHTML.pm +345 -0
  61. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/HTML.pm +398 -0
  62. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/HTMLBase.pm +3693 -0
  63. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ClassHierarchy.pm +860 -0
  64. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ClassHierarchy/Class.pm +412 -0
  65. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ClassHierarchy/File.pm +157 -0
  66. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ConfigFile.pm +497 -0
  67. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Constants.pm +165 -0
  68. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/DefineMembers.pm +100 -0
  69. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Error.pm +305 -0
  70. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/File.pm +540 -0
  71. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ImageReferenceTable.pm +383 -0
  72. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ImageReferenceTable/Reference.pm +44 -0
  73. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ImageReferenceTable/String.pm +110 -0
  74. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages.pm +1475 -0
  75. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/ActionScript.pm +1473 -0
  76. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Ada.pm +38 -0
  77. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Advanced.pm +828 -0
  78. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Advanced/Scope.pm +95 -0
  79. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Advanced/ScopeChange.pm +70 -0
  80. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Base.pm +832 -0
  81. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/CSharp.pm +1484 -0
  82. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/PLSQL.pm +319 -0
  83. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Pascal.pm +143 -0
  84. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Perl.pm +1370 -0
  85. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Prototype.pm +92 -0
  86. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Prototype/Parameter.pm +87 -0
  87. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Simple.pm +503 -0
  88. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Tcl.pm +219 -0
  89. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Menu.pm +3406 -0
  90. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Menu/Entry.pm +201 -0
  91. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/NDMarkup.pm +76 -0
  92. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser.pm +1331 -0
  93. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser/JavaDoc.pm +464 -0
  94. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser/Native.pm +1060 -0
  95. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser/ParsedTopic.pm +253 -0
  96. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Project.pm +1402 -0
  97. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Project/ImageFile.pm +160 -0
  98. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Project/SourceFile.pm +113 -0
  99. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ReferenceString.pm +334 -0
  100. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Settings.pm +1418 -0
  101. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Settings/BuildTarget.pm +66 -0
  102. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB.pm +678 -0
  103. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/Extension.pm +84 -0
  104. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/File.pm +129 -0
  105. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/Item.pm +201 -0
  106. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/ItemDefinition.pm +45 -0
  107. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/WatchedFileDefinitions.pm +159 -0
  108. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/StatusMessage.pm +102 -0
  109. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolString.pm +212 -0
  110. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable.pm +1984 -0
  111. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/File.pm +186 -0
  112. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/IndexElement.pm +522 -0
  113. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/Reference.pm +273 -0
  114. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/ReferenceTarget.pm +97 -0
  115. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/Symbol.pm +428 -0
  116. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/SymbolDefinition.pm +96 -0
  117. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Topics.pm +1319 -0
  118. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Topics/Type.pm +151 -0
  119. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Version.pm +384 -0
  120. data/template/assets/naturaldocs/NaturalDocs/NaturalDocs +400 -0
  121. data/template/assets/naturaldocs/NaturalDocs/NaturalDocs.bat +17 -0
  122. data/template/assets/naturaldocs/NaturalDocs/Styles/Default.css +767 -0
  123. data/template/assets/naturaldocs/NaturalDocs/Styles/Roman.css +765 -0
  124. data/template/assets/naturaldocs/NaturalDocs/Styles/Small.css +763 -0
  125. data/template/assets/utilities/pngout +0 -0
  126. data/template/deploy/public_html/.htaccess +0 -0
  127. data/template/documentation/js/.htaccess +0 -0
  128. data/template/src/html/.htaccess +76 -0
  129. data/template/src/html/css/cmn/global.css +96 -0
  130. data/template/src/html/css/cmn/ie.css +15 -0
  131. data/template/src/html/css/cmn/ie6.css +15 -0
  132. data/template/src/html/images/cmn/.htaccess +0 -0
  133. data/template/src/html/images/tmp/.htaccess +0 -0
  134. data/template/src/html/includes/debug.inc +5 -0
  135. data/template/src/html/includes/footer.inc +52 -0
  136. data/template/src/html/includes/header.inc +61 -0
  137. data/template/src/html/includes/html.inc +3 -0
  138. data/template/src/html/includes/namespace.inc +19 -0
  139. data/template/src/html/includes/page.inc +151 -0
  140. data/template/src/html/index.html +35 -0
  141. data/template/src/html/js/cmn/bootstrap.js +74 -0
  142. data/template/src/html/js/cmn/global.js +142 -0
  143. data/template/src/html/js/cmn/lib/LAB.js +348 -0
  144. data/template/src/html/min/.htaccess +4 -0
  145. data/template/src/html/min/MinifyCLI.php +19 -0
  146. data/template/src/html/min/README.txt +132 -0
  147. data/template/src/html/min/builder/_index.js +242 -0
  148. data/template/src/html/min/builder/bm.js +36 -0
  149. data/template/src/html/min/builder/index.php +182 -0
  150. data/template/src/html/min/builder/ocCheck.php +36 -0
  151. data/template/src/html/min/builder/rewriteTest.js +1 -0
  152. data/template/src/html/min/config.php +187 -0
  153. data/template/src/html/min/groupsConfig.php +34 -0
  154. data/template/src/html/min/index.php +66 -0
  155. data/template/src/html/min/lib/FirePHP.php +1370 -0
  156. data/template/src/html/min/lib/HTTP/ConditionalGet.php +348 -0
  157. data/template/src/html/min/lib/HTTP/Encoder.php +326 -0
  158. data/template/src/html/min/lib/JSMin.php +314 -0
  159. data/template/src/html/min/lib/JSMinPlus.php +1872 -0
  160. data/template/src/html/min/lib/Minify.php +532 -0
  161. data/template/src/html/min/lib/Minify/Build.php +103 -0
  162. data/template/src/html/min/lib/Minify/CSS.php +83 -0
  163. data/template/src/html/min/lib/Minify/CSS/Compressor.php +250 -0
  164. data/template/src/html/min/lib/Minify/CSS/UriRewriter.php +270 -0
  165. data/template/src/html/min/lib/Minify/Cache/APC.php +130 -0
  166. data/template/src/html/min/lib/Minify/Cache/File.php +125 -0
  167. data/template/src/html/min/lib/Minify/Cache/Memcache.php +137 -0
  168. data/template/src/html/min/lib/Minify/ClosureCompiler.php +85 -0
  169. data/template/src/html/min/lib/Minify/CommentPreserver.php +90 -0
  170. data/template/src/html/min/lib/Minify/Controller/Base.php +202 -0
  171. data/template/src/html/min/lib/Minify/Controller/Files.php +78 -0
  172. data/template/src/html/min/lib/Minify/Controller/Groups.php +94 -0
  173. data/template/src/html/min/lib/Minify/Controller/MinApp.php +132 -0
  174. data/template/src/html/min/lib/Minify/Controller/Page.php +82 -0
  175. data/template/src/html/min/lib/Minify/Controller/Version1.php +118 -0
  176. data/template/src/html/min/lib/Minify/HTML.php +245 -0
  177. data/template/src/html/min/lib/Minify/ImportProcessor.php +157 -0
  178. data/template/src/html/min/lib/Minify/Lines.php +131 -0
  179. data/template/src/html/min/lib/Minify/Logger.php +45 -0
  180. data/template/src/html/min/lib/Minify/Packer.php +37 -0
  181. data/template/src/html/min/lib/Minify/Source.php +187 -0
  182. data/template/src/html/min/lib/Minify/YUICompressor.php +139 -0
  183. data/template/src/html/min/lib/Solar/Dir.php +199 -0
  184. data/template/src/html/min/lib/closure-compiler.jar +0 -0
  185. data/template/src/html/min/lib/yuicompressor-2.4.2.jar +0 -0
  186. data/template/src/html/min/utils.php +90 -0
  187. data/template/src/templates/css/template.css +7 -0
  188. data/template/src/templates/js/template.js +72 -0
  189. data/template/src/templates/template.html +18 -0
  190. data/template/src/yaml/config.yml +46 -0
  191. data/template/src/yaml/deploy.yml +35 -0
  192. data/test/bixbite_test.rb +7 -0
  193. data/test/test_helper.rb +10 -0
  194. metadata +278 -0
@@ -0,0 +1,348 @@
1
+ <?php
2
+ /**
3
+ * Class HTTP_ConditionalGet
4
+ * @package Minify
5
+ * @subpackage HTTP
6
+ */
7
+
8
+ /**
9
+ * Implement conditional GET via a timestamp or hash of content
10
+ *
11
+ * E.g. Content from DB with update time:
12
+ * <code>
13
+ * list($updateTime, $content) = getDbUpdateAndContent();
14
+ * $cg = new HTTP_ConditionalGet(array(
15
+ * 'lastModifiedTime' => $updateTime
16
+ * ,'isPublic' => true
17
+ * ));
18
+ * $cg->sendHeaders();
19
+ * if ($cg->cacheIsValid) {
20
+ * exit();
21
+ * }
22
+ * echo $content;
23
+ * </code>
24
+ *
25
+ * E.g. Shortcut for the above
26
+ * <code>
27
+ * HTTP_ConditionalGet::check($updateTime, true); // exits if client has cache
28
+ * echo $content;
29
+ * </code>
30
+ *
31
+ * E.g. Content from DB with no update time:
32
+ * <code>
33
+ * $content = getContentFromDB();
34
+ * $cg = new HTTP_ConditionalGet(array(
35
+ * 'contentHash' => md5($content)
36
+ * ));
37
+ * $cg->sendHeaders();
38
+ * if ($cg->cacheIsValid) {
39
+ * exit();
40
+ * }
41
+ * echo $content;
42
+ * </code>
43
+ *
44
+ * E.g. Static content with some static includes:
45
+ * <code>
46
+ * // before content
47
+ * $cg = new HTTP_ConditionalGet(array(
48
+ * 'lastUpdateTime' => max(
49
+ * filemtime(__FILE__)
50
+ * ,filemtime('/path/to/header.inc')
51
+ * ,filemtime('/path/to/footer.inc')
52
+ * )
53
+ * ));
54
+ * $cg->sendHeaders();
55
+ * if ($cg->cacheIsValid) {
56
+ * exit();
57
+ * }
58
+ * </code>
59
+ * @package Minify
60
+ * @subpackage HTTP
61
+ * @author Stephen Clay <steve@mrclay.org>
62
+ */
63
+ class HTTP_ConditionalGet {
64
+
65
+ /**
66
+ * Does the client have a valid copy of the requested resource?
67
+ *
68
+ * You'll want to check this after instantiating the object. If true, do
69
+ * not send content, just call sendHeaders() if you haven't already.
70
+ *
71
+ * @var bool
72
+ */
73
+ public $cacheIsValid = null;
74
+
75
+ /**
76
+ * @param array $spec options
77
+ *
78
+ * 'isPublic': (bool) if true, the Cache-Control header will contain
79
+ * "public", allowing proxies to cache the content. Otherwise "private" will
80
+ * be sent, allowing only browser caching. (default false)
81
+ *
82
+ * 'lastModifiedTime': (int) if given, both ETag AND Last-Modified headers
83
+ * will be sent with content. This is recommended.
84
+ *
85
+ * 'encoding': (string) if set, the header "Vary: Accept-Encoding" will
86
+ * always be sent and a truncated version of the encoding will be appended
87
+ * to the ETag. E.g. "pub123456;gz". This will also trigger a more lenient
88
+ * checking of the client's If-None-Match header, as the encoding portion of
89
+ * the ETag will be stripped before comparison.
90
+ *
91
+ * 'contentHash': (string) if given, only the ETag header can be sent with
92
+ * content (only HTTP1.1 clients can conditionally GET). The given string
93
+ * should be short with no quote characters and always change when the
94
+ * resource changes (recommend md5()). This is not needed/used if
95
+ * lastModifiedTime is given.
96
+ *
97
+ * 'eTag': (string) if given, this will be used as the ETag header rather
98
+ * than values based on lastModifiedTime or contentHash. Also the encoding
99
+ * string will not be appended to the given value as described above.
100
+ *
101
+ * 'invalidate': (bool) if true, the client cache will be considered invalid
102
+ * without testing. Effectively this disables conditional GET.
103
+ * (default false)
104
+ *
105
+ * 'maxAge': (int) if given, this will set the Cache-Control max-age in
106
+ * seconds, and also set the Expires header to the equivalent GMT date.
107
+ * After the max-age period has passed, the browser will again send a
108
+ * conditional GET to revalidate its cache.
109
+ *
110
+ * @return null
111
+ */
112
+ public function __construct($spec)
113
+ {
114
+ $scope = (isset($spec['isPublic']) && $spec['isPublic'])
115
+ ? 'public'
116
+ : 'private';
117
+ $maxAge = 0;
118
+ // backwards compatibility (can be removed later)
119
+ if (isset($spec['setExpires'])
120
+ && is_numeric($spec['setExpires'])
121
+ && ! isset($spec['maxAge'])) {
122
+ $spec['maxAge'] = $spec['setExpires'] - $_SERVER['REQUEST_TIME'];
123
+ }
124
+ if (isset($spec['maxAge'])) {
125
+ $maxAge = $spec['maxAge'];
126
+ $this->_headers['Expires'] = self::gmtDate(
127
+ $_SERVER['REQUEST_TIME'] + $spec['maxAge']
128
+ );
129
+ }
130
+ $etagAppend = '';
131
+ if (isset($spec['encoding'])) {
132
+ $this->_stripEtag = true;
133
+ $this->_headers['Vary'] = 'Accept-Encoding';
134
+ if ('' !== $spec['encoding']) {
135
+ if (0 === strpos($spec['encoding'], 'x-')) {
136
+ $spec['encoding'] = substr($spec['encoding'], 2);
137
+ }
138
+ $etagAppend = ';' . substr($spec['encoding'], 0, 2);
139
+ }
140
+ }
141
+ if (isset($spec['lastModifiedTime'])) {
142
+ $this->_setLastModified($spec['lastModifiedTime']);
143
+ if (isset($spec['eTag'])) { // Use it
144
+ $this->_setEtag($spec['eTag'], $scope);
145
+ } else { // base both headers on time
146
+ $this->_setEtag($spec['lastModifiedTime'] . $etagAppend, $scope);
147
+ }
148
+ } elseif (isset($spec['eTag'])) { // Use it
149
+ $this->_setEtag($spec['eTag'], $scope);
150
+ } elseif (isset($spec['contentHash'])) { // Use the hash as the ETag
151
+ $this->_setEtag($spec['contentHash'] . $etagAppend, $scope);
152
+ }
153
+ $this->_headers['Cache-Control'] = "max-age={$maxAge}, {$scope}";
154
+ // invalidate cache if disabled, otherwise check
155
+ $this->cacheIsValid = (isset($spec['invalidate']) && $spec['invalidate'])
156
+ ? false
157
+ : $this->_isCacheValid();
158
+ }
159
+
160
+ /**
161
+ * Get array of output headers to be sent
162
+ *
163
+ * In the case of 304 responses, this array will only contain the response
164
+ * code header: array('_responseCode' => 'HTTP/1.0 304 Not Modified')
165
+ *
166
+ * Otherwise something like:
167
+ * <code>
168
+ * array(
169
+ * 'Cache-Control' => 'max-age=0, public'
170
+ * ,'ETag' => '"foobar"'
171
+ * )
172
+ * </code>
173
+ *
174
+ * @return array
175
+ */
176
+ public function getHeaders()
177
+ {
178
+ return $this->_headers;
179
+ }
180
+
181
+ /**
182
+ * Set the Content-Length header in bytes
183
+ *
184
+ * With most PHP configs, as long as you don't flush() output, this method
185
+ * is not needed and PHP will buffer all output and set Content-Length for
186
+ * you. Otherwise you'll want to call this to let the client know up front.
187
+ *
188
+ * @param int $bytes
189
+ *
190
+ * @return int copy of input $bytes
191
+ */
192
+ public function setContentLength($bytes)
193
+ {
194
+ return $this->_headers['Content-Length'] = $bytes;
195
+ }
196
+
197
+ /**
198
+ * Send headers
199
+ *
200
+ * @see getHeaders()
201
+ *
202
+ * Note this doesn't "clear" the headers. Calling sendHeaders() will
203
+ * call header() again (but probably have not effect) and getHeaders() will
204
+ * still return the headers.
205
+ *
206
+ * @return null
207
+ */
208
+ public function sendHeaders()
209
+ {
210
+ $headers = $this->_headers;
211
+ if (array_key_exists('_responseCode', $headers)) {
212
+ header($headers['_responseCode']);
213
+ unset($headers['_responseCode']);
214
+ }
215
+ foreach ($headers as $name => $val) {
216
+ header($name . ': ' . $val);
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Exit if the client's cache is valid for this resource
222
+ *
223
+ * This is a convenience method for common use of the class
224
+ *
225
+ * @param int $lastModifiedTime if given, both ETag AND Last-Modified headers
226
+ * will be sent with content. This is recommended.
227
+ *
228
+ * @param bool $isPublic (default false) if true, the Cache-Control header
229
+ * will contain "public", allowing proxies to cache the content. Otherwise
230
+ * "private" will be sent, allowing only browser caching.
231
+ *
232
+ * @param array $options (default empty) additional options for constructor
233
+ *
234
+ * @return null
235
+ */
236
+ public static function check($lastModifiedTime = null, $isPublic = false, $options = array())
237
+ {
238
+ if (null !== $lastModifiedTime) {
239
+ $options['lastModifiedTime'] = (int)$lastModifiedTime;
240
+ }
241
+ $options['isPublic'] = (bool)$isPublic;
242
+ $cg = new HTTP_ConditionalGet($options);
243
+ $cg->sendHeaders();
244
+ if ($cg->cacheIsValid) {
245
+ exit();
246
+ }
247
+ }
248
+
249
+
250
+ /**
251
+ * Get a GMT formatted date for use in HTTP headers
252
+ *
253
+ * <code>
254
+ * header('Expires: ' . HTTP_ConditionalGet::gmtdate($time));
255
+ * </code>
256
+ *
257
+ * @param int $time unix timestamp
258
+ *
259
+ * @return string
260
+ */
261
+ public static function gmtDate($time)
262
+ {
263
+ return gmdate('D, d M Y H:i:s \G\M\T', $time);
264
+ }
265
+
266
+ protected $_headers = array();
267
+ protected $_lmTime = null;
268
+ protected $_etag = null;
269
+ protected $_stripEtag = false;
270
+
271
+ protected function _setEtag($hash, $scope)
272
+ {
273
+ $this->_etag = '"' . substr($scope, 0, 3) . $hash . '"';
274
+ $this->_headers['ETag'] = $this->_etag;
275
+ }
276
+
277
+ protected function _setLastModified($time)
278
+ {
279
+ $this->_lmTime = (int)$time;
280
+ $this->_headers['Last-Modified'] = self::gmtDate($time);
281
+ }
282
+
283
+ /**
284
+ * Determine validity of client cache and queue 304 header if valid
285
+ */
286
+ protected function _isCacheValid()
287
+ {
288
+ if (null === $this->_etag) {
289
+ // lmTime is copied to ETag, so this condition implies that the
290
+ // server sent neither ETag nor Last-Modified, so the client can't
291
+ // possibly has a valid cache.
292
+ return false;
293
+ }
294
+ $isValid = ($this->resourceMatchedEtag() || $this->resourceNotModified());
295
+ if ($isValid) {
296
+ $this->_headers['_responseCode'] = 'HTTP/1.0 304 Not Modified';
297
+ }
298
+ return $isValid;
299
+ }
300
+
301
+ protected function resourceMatchedEtag()
302
+ {
303
+ if (!isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
304
+ return false;
305
+ }
306
+ $clientEtagList = get_magic_quotes_gpc()
307
+ ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])
308
+ : $_SERVER['HTTP_IF_NONE_MATCH'];
309
+ $clientEtags = explode(',', $clientEtagList);
310
+
311
+ $compareTo = $this->normalizeEtag($this->_etag);
312
+ foreach ($clientEtags as $clientEtag) {
313
+ if ($this->normalizeEtag($clientEtag) === $compareTo) {
314
+ // respond with the client's matched ETag, even if it's not what
315
+ // we would've sent by default
316
+ $this->_headers['ETag'] = trim($clientEtag);
317
+ return true;
318
+ }
319
+ }
320
+ return false;
321
+ }
322
+
323
+ protected function normalizeEtag($etag) {
324
+ $etag = trim($etag);
325
+ return $this->_stripEtag
326
+ ? preg_replace('/;\\w\\w"$/', '"', $etag)
327
+ : $etag;
328
+ }
329
+
330
+ protected function resourceNotModified()
331
+ {
332
+ if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
333
+ return false;
334
+ }
335
+ $ifModifiedSince = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
336
+ if (false !== ($semicolon = strrpos($ifModifiedSince, ';'))) {
337
+ // IE has tacked on extra data to this header, strip it
338
+ $ifModifiedSince = substr($ifModifiedSince, 0, $semicolon);
339
+ }
340
+ if ($ifModifiedSince == self::gmtDate($this->_lmTime)) {
341
+ // Apache 2.2's behavior. If there was no ETag match, send the
342
+ // non-encoded version of the ETag value.
343
+ $this->_headers['ETag'] = $this->normalizeEtag($this->_etag);
344
+ return true;
345
+ }
346
+ return false;
347
+ }
348
+ }
@@ -0,0 +1,326 @@
1
+ <?php
2
+ /**
3
+ * Class HTTP_Encoder
4
+ * @package Minify
5
+ * @subpackage HTTP
6
+ */
7
+
8
+ /**
9
+ * Encode and send gzipped/deflated content
10
+ *
11
+ * The "Vary: Accept-Encoding" header is sent. If the client allows encoding,
12
+ * Content-Encoding and Content-Length are added.
13
+ *
14
+ * <code>
15
+ * // Send a CSS file, compressed if possible
16
+ * $he = new HTTP_Encoder(array(
17
+ * 'content' => file_get_contents($cssFile)
18
+ * ,'type' => 'text/css'
19
+ * ));
20
+ * $he->encode();
21
+ * $he->sendAll();
22
+ * </code>
23
+ *
24
+ * <code>
25
+ * // Shortcut to encoding output
26
+ * header('Content-Type: text/css'); // needed if not HTML
27
+ * HTTP_Encoder::output($css);
28
+ * </code>
29
+ *
30
+ * <code>
31
+ * // Just sniff for the accepted encoding
32
+ * $encoding = HTTP_Encoder::getAcceptedEncoding();
33
+ * </code>
34
+ *
35
+ * For more control over headers, use getHeaders() and getData() and send your
36
+ * own output.
37
+ *
38
+ * Note: If you don't need header mgmt, use PHP's native gzencode, gzdeflate,
39
+ * and gzcompress functions for gzip, deflate, and compress-encoding
40
+ * respectively.
41
+ *
42
+ * @package Minify
43
+ * @subpackage HTTP
44
+ * @author Stephen Clay <steve@mrclay.org>
45
+ */
46
+ class HTTP_Encoder {
47
+
48
+ /**
49
+ * Should the encoder allow HTTP encoding to IE6?
50
+ *
51
+ * If you have many IE6 users and the bandwidth savings is worth troubling
52
+ * some of them, set this to true.
53
+ *
54
+ * By default, encoding is only offered to IE7+. When this is true,
55
+ * getAcceptedEncoding() will return an encoding for IE6 if its user agent
56
+ * string contains "SV1". This has been documented in many places as "safe",
57
+ * but there seem to be remaining, intermittent encoding bugs in patched
58
+ * IE6 on the wild web.
59
+ *
60
+ * @var bool
61
+ */
62
+ public static $encodeToIe6 = false;
63
+
64
+
65
+ /**
66
+ * Default compression level for zlib operations
67
+ *
68
+ * This level is used if encode() is not given a $compressionLevel
69
+ *
70
+ * @var int
71
+ */
72
+ public static $compressionLevel = 6;
73
+
74
+
75
+ /**
76
+ * Get an HTTP Encoder object
77
+ *
78
+ * @param array $spec options
79
+ *
80
+ * 'content': (string required) content to be encoded
81
+ *
82
+ * 'type': (string) if set, the Content-Type header will have this value.
83
+ *
84
+ * 'method: (string) only set this if you are forcing a particular encoding
85
+ * method. If not set, the best method will be chosen by getAcceptedEncoding()
86
+ * The available methods are 'gzip', 'deflate', 'compress', and '' (no
87
+ * encoding)
88
+ *
89
+ * @return null
90
+ */
91
+ public function __construct($spec)
92
+ {
93
+ $this->_content = $spec['content'];
94
+ $this->_headers['Content-Length'] = (string)strlen($this->_content);
95
+ if (isset($spec['type'])) {
96
+ $this->_headers['Content-Type'] = $spec['type'];
97
+ }
98
+ if (isset($spec['method'])
99
+ && in_array($spec['method'], array('gzip', 'deflate', 'compress', '')))
100
+ {
101
+ $this->_encodeMethod = array($spec['method'], $spec['method']);
102
+ } else {
103
+ $this->_encodeMethod = self::getAcceptedEncoding();
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Get content in current form
109
+ *
110
+ * Call after encode() for encoded content.
111
+ *
112
+ * return string
113
+ */
114
+ public function getContent()
115
+ {
116
+ return $this->_content;
117
+ }
118
+
119
+ /**
120
+ * Get array of output headers to be sent
121
+ *
122
+ * E.g.
123
+ * <code>
124
+ * array(
125
+ * 'Content-Length' => '615'
126
+ * ,'Content-Encoding' => 'x-gzip'
127
+ * ,'Vary' => 'Accept-Encoding'
128
+ * )
129
+ * </code>
130
+ *
131
+ * @return array
132
+ */
133
+ public function getHeaders()
134
+ {
135
+ return $this->_headers;
136
+ }
137
+
138
+ /**
139
+ * Send output headers
140
+ *
141
+ * You must call this before headers are sent and it probably cannot be
142
+ * used in conjunction with zlib output buffering / mod_gzip. Errors are
143
+ * not handled purposefully.
144
+ *
145
+ * @see getHeaders()
146
+ *
147
+ * @return null
148
+ */
149
+ public function sendHeaders()
150
+ {
151
+ foreach ($this->_headers as $name => $val) {
152
+ header($name . ': ' . $val);
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Send output headers and content
158
+ *
159
+ * A shortcut for sendHeaders() and echo getContent()
160
+ *
161
+ * You must call this before headers are sent and it probably cannot be
162
+ * used in conjunction with zlib output buffering / mod_gzip. Errors are
163
+ * not handled purposefully.
164
+ *
165
+ * @return null
166
+ */
167
+ public function sendAll()
168
+ {
169
+ $this->sendHeaders();
170
+ echo $this->_content;
171
+ }
172
+
173
+ /**
174
+ * Determine the client's best encoding method from the HTTP Accept-Encoding
175
+ * header.
176
+ *
177
+ * If no Accept-Encoding header is set, or the browser is IE before v6 SP2,
178
+ * this will return ('', ''), the "identity" encoding.
179
+ *
180
+ * A syntax-aware scan is done of the Accept-Encoding, so the method must
181
+ * be non 0. The methods are favored in order of gzip, deflate, then
182
+ * compress. Deflate is always smallest and generally faster, but is
183
+ * rarely sent by servers, so client support could be buggier.
184
+ *
185
+ * @param bool $allowCompress allow the older compress encoding
186
+ *
187
+ * @param bool $allowDeflate allow the more recent deflate encoding
188
+ *
189
+ * @return array two values, 1st is the actual encoding method, 2nd is the
190
+ * alias of that method to use in the Content-Encoding header (some browsers
191
+ * call gzip "x-gzip" etc.)
192
+ */
193
+ public static function getAcceptedEncoding($allowCompress = true, $allowDeflate = true)
194
+ {
195
+ // @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
196
+
197
+ if (! isset($_SERVER['HTTP_ACCEPT_ENCODING'])
198
+ || self::_isBuggyIe())
199
+ {
200
+ return array('', '');
201
+ }
202
+ $ae = $_SERVER['HTTP_ACCEPT_ENCODING'];
203
+ // gzip checks (quick)
204
+ if (0 === strpos($ae, 'gzip,') // most browsers
205
+ || 0 === strpos($ae, 'deflate, gzip,') // opera
206
+ ) {
207
+ return array('gzip', 'gzip');
208
+ }
209
+ // gzip checks (slow)
210
+ if (preg_match(
211
+ '@(?:^|,)\\s*((?:x-)?gzip)\\s*(?:$|,|;\\s*q=(?:0\\.|1))@'
212
+ ,$ae
213
+ ,$m)) {
214
+ return array('gzip', $m[1]);
215
+ }
216
+ if ($allowDeflate) {
217
+ // deflate checks
218
+ $aeRev = strrev($ae);
219
+ if (0 === strpos($aeRev, 'etalfed ,') // ie, webkit
220
+ || 0 === strpos($aeRev, 'etalfed,') // gecko
221
+ || 0 === strpos($ae, 'deflate,') // opera
222
+ // slow parsing
223
+ || preg_match(
224
+ '@(?:^|,)\\s*deflate\\s*(?:$|,|;\\s*q=(?:0\\.|1))@', $ae)) {
225
+ return array('deflate', 'deflate');
226
+ }
227
+ }
228
+ if ($allowCompress && preg_match(
229
+ '@(?:^|,)\\s*((?:x-)?compress)\\s*(?:$|,|;\\s*q=(?:0\\.|1))@'
230
+ ,$ae
231
+ ,$m)) {
232
+ return array('compress', $m[1]);
233
+ }
234
+ return array('', '');
235
+ }
236
+
237
+ /**
238
+ * Encode (compress) the content
239
+ *
240
+ * If the encode method is '' (none) or compression level is 0, or the 'zlib'
241
+ * extension isn't loaded, we return false.
242
+ *
243
+ * Then the appropriate gz_* function is called to compress the content. If
244
+ * this fails, false is returned.
245
+ *
246
+ * The header "Vary: Accept-Encoding" is added. If encoding is successful,
247
+ * the Content-Length header is updated, and Content-Encoding is also added.
248
+ *
249
+ * @param int $compressionLevel given to zlib functions. If not given, the
250
+ * class default will be used.
251
+ *
252
+ * @return bool success true if the content was actually compressed
253
+ */
254
+ public function encode($compressionLevel = null)
255
+ {
256
+ $this->_headers['Vary'] = 'Accept-Encoding';
257
+ if (null === $compressionLevel) {
258
+ $compressionLevel = self::$compressionLevel;
259
+ }
260
+ if ('' === $this->_encodeMethod[0]
261
+ || ($compressionLevel == 0)
262
+ || !extension_loaded('zlib'))
263
+ {
264
+ return false;
265
+ }
266
+ if ($this->_encodeMethod[0] === 'deflate') {
267
+ $encoded = gzdeflate($this->_content, $compressionLevel);
268
+ } elseif ($this->_encodeMethod[0] === 'gzip') {
269
+ $encoded = gzencode($this->_content, $compressionLevel);
270
+ } else {
271
+ $encoded = gzcompress($this->_content, $compressionLevel);
272
+ }
273
+ if (false === $encoded) {
274
+ return false;
275
+ }
276
+ $this->_headers['Content-Length'] = strlen($encoded);
277
+ $this->_headers['Content-Encoding'] = $this->_encodeMethod[1];
278
+ $this->_content = $encoded;
279
+ return true;
280
+ }
281
+
282
+ /**
283
+ * Encode and send appropriate headers and content
284
+ *
285
+ * This is a convenience method for common use of the class
286
+ *
287
+ * @param string $content
288
+ *
289
+ * @param int $compressionLevel given to zlib functions. If not given, the
290
+ * class default will be used.
291
+ *
292
+ * @return bool success true if the content was actually compressed
293
+ */
294
+ public static function output($content, $compressionLevel = null)
295
+ {
296
+ if (null === $compressionLevel) {
297
+ $compressionLevel = self::$compressionLevel;
298
+ }
299
+ $he = new HTTP_Encoder(array('content' => $content));
300
+ $ret = $he->encode($compressionLevel);
301
+ $he->sendAll();
302
+ return $ret;
303
+ }
304
+
305
+ protected $_content = '';
306
+ protected $_headers = array();
307
+ protected $_encodeMethod = array('', '');
308
+
309
+ /**
310
+ * Is the browser an IE version earlier than 6 SP2?
311
+ */
312
+ protected static function _isBuggyIe()
313
+ {
314
+ $ua = $_SERVER['HTTP_USER_AGENT'];
315
+ // quick escape for non-IEs
316
+ if (0 !== strpos($ua, 'Mozilla/4.0 (compatible; MSIE ')
317
+ || false !== strpos($ua, 'Opera')) {
318
+ return false;
319
+ }
320
+ // no regex = faaast
321
+ $version = (float)substr($ua, 30);
322
+ return self::$encodeToIe6
323
+ ? ($version < 6 || ($version == 6 && false === strpos($ua, 'SV1')))
324
+ : ($version < 7);
325
+ }
326
+ }