response.class.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <?php
  2. namespace Juju\Http;
  3. require_once(realpath(dirname(__DIR__).'/events.trait.php'));
  4. require_once(realpath(dirname(__DIR__).'/App/router.class.php'));
  5. use \Juju\{App\Router, Events};
  6. class Response implements \JsonSerializable {
  7. use Events;
  8. public $output = '';
  9. public $body = '';
  10. private $code = 200;
  11. public $headers = [];
  12. protected $open = true;
  13. protected $shutdown = false;
  14. public function __construct(){}
  15. public function __toString(){
  16. return $this->body;
  17. }
  18. public function jsonSerialize(){
  19. return [
  20. 'code'=> $this->code,
  21. 'headers'=> $this->headers,
  22. 'body'=> $this->body
  23. ];
  24. }
  25. public function clear(){
  26. if($this->open){
  27. $this->fire('clear');
  28. $this->body = '';
  29. }
  30. return $this;
  31. }
  32. public function clear_headers(){
  33. if($this->open){
  34. $this->fire('clear_headers');
  35. $this->headers = [];
  36. }
  37. return $this;
  38. }
  39. public function clear_header(string $name){
  40. foreach($this->headers as $key => $header){
  41. if($header[0] == $name){
  42. $this->fire('clear_header', $name);
  43. array_splice($this->headers, $key, 1);
  44. }
  45. }
  46. return $this;
  47. }
  48. public function write(string $chunk){
  49. $this->fire('write', $chunk);
  50. if($this->open){
  51. $this->body .= $chunk;
  52. $this->clear_header('Content-Length')
  53. ->header('Content-Length', strlen($this->body));
  54. }
  55. return $this;
  56. }
  57. public function json($json){
  58. if(is_array($json)){
  59. array_walk_recursive($json, function(&$item, $key){
  60. if(!mb_detect_encoding($item, 'utf-8', true)){
  61. $item = utf8_encode($item);
  62. }
  63. });
  64. }
  65. $this->fire('json', $json);
  66. $this->write(json_encode($json));
  67. if(json_last_error() != JSON_ERROR_NONE){
  68. throw new \Exception(json_last_error_msg());
  69. }
  70. return $this;
  71. }
  72. public function header(string $name, string $value = null){
  73. if(is_null($value)){
  74. $headers = array_filter($this->headers,function($header) use($name){
  75. return $header[0] == $name;
  76. });
  77. return end($headers)[1];
  78. }else{
  79. if($this->open){
  80. if($this->fire('header', $name, $value) !== false){
  81. $this->headers[] = [
  82. $name,
  83. $value
  84. ];
  85. }
  86. }
  87. }
  88. return $this;
  89. }
  90. public function redirect(string $url){
  91. $this->fire('redirect', $url);
  92. $this->header('Location', Router::url($url));
  93. return $this;
  94. }
  95. public function end(string $chunk=''){
  96. if($this->open){
  97. $this->write($chunk);
  98. $this->fire('end');
  99. $this->open = false;
  100. }
  101. return $this;
  102. }
  103. public function img(Image $img, string $type = null){
  104. if(!$type){
  105. $type = $img->type;
  106. }
  107. $this->fire('image', $img, $type);
  108. $this->clear_header('Content-Type')
  109. ->header('Content-Type', 'image/'.$type);
  110. if(!is_a($img, 'Image')){
  111. $img = new Image(100, 20);
  112. $img->text('Invalid Image',0,0,'black',12);
  113. }
  114. ob_start();
  115. $img();
  116. $this->write(ob_get_contents());
  117. ob_end_clean();
  118. return $this;
  119. }
  120. public function code(int $code=null){
  121. if(is_null($code)){
  122. return $this->code;
  123. }
  124. $this->fire('code', $code);
  125. $this->code = $code;
  126. return $this;
  127. }
  128. public function shutdown(){
  129. if(!$this->shutdown){
  130. $this->shutdown = true;
  131. $this->fire('beforeshutdown');
  132. if($this->open){
  133. $this->end();
  134. }
  135. $this->fire('shutdown');
  136. http_response_code($this->code);
  137. foreach($this->headers as $k => $header){
  138. header("{$header[0]}: $header[1]");
  139. }
  140. echo $this->body;
  141. flush();
  142. $this->fire('aftershutdown');
  143. }
  144. return $this;
  145. }
  146. public function open(bool $force = false){
  147. if($force){
  148. $this->shutdown = false;
  149. }
  150. if(!$this->shutdown){
  151. $this->open = true;
  152. }
  153. return $this;
  154. }
  155. public static function locale(string $locale, string $domain, string $folder, string $codeset = 'UTF-8'){
  156. $path = realpath($folder);
  157. if($path !== false){
  158. bindtextdomain($domain, $path);
  159. textdomain($domain);
  160. bind_textdomain_codeset($domain, $codeset);
  161. $orig_locale = $locale;
  162. if(!file_exists("{$path}/$locale/LC_MESSAGES/{$domain}.mo")){
  163. $locale = \Locale::getPrimaryLanguage($locale);
  164. if(!file_exists("{$path}/$locale/LC_MESSAGES/{$domain}.mo")){
  165. $locale = \Locale::getDefault();
  166. if(!file_exists("{$path}/$locale/LC_MESSAGES/{$domain}.mo")){
  167. $dir = dir("{$path}/");
  168. do{
  169. $locale = $dir->read();
  170. if($locale === false){
  171. trigger_error("Unable to find fallback locale for {$orig_locale}", E_USER_WARNING);
  172. break;
  173. }
  174. }while(!file_exists("{$path}/$locale/LC_MESSAGES/{$domain}.mo"));
  175. }
  176. }
  177. }
  178. }else{
  179. trigger_error("Locale folder {$folder} missing", E_USER_WARNING);
  180. }
  181. \Locale::setDefault($locale);
  182. }
  183. }
  184. ?>