bixbite 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }