ILIAS  trunk Revision v11.0_alpha-1731-gff9cd7e2bd3
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator Modules Pages
DefaultResponseSenderStrategy.php
Go to the documentation of this file.
1 <?php
2 
20 
22 
32 {
36  private const METHOD_FPASSTHRU = 'fpassthru';
40  private const METHOD_READFILE = 'readfile';
41  private string $method = self::METHOD_FPASSTHRU;
42  private int $chunk_size;
43  private int $memory_limit;
44 
45  public function __construct()
46  {
47  $this->memory_limit = $this->initMemoryLimit();
48  $this->chunk_size = $this->initChunkSize();
49  }
50 
51  private function initMemoryLimit(): int
52  {
53  $ini_memory_limit = ini_get('memory_limit');
54  $memory_limit = null;
55  if (preg_match('/^(\d+)(.)$/', $ini_memory_limit, $matches)) {
56  $memory_limit = match ($matches[2] ?? null) {
57  'G' => (int) $matches[1] * 1024 * 1024 * 1024,
58  'M' => (int) $matches[1] * 1024 * 1024,
59  'K' => (int) $matches[1] * 1024,
60  default => (int) $matches[1],
61  };
62  }
63 
64  return $memory_limit ?? 128 * 1024 * 1024;
65  }
66 
67  private function initChunkSize(): int
68  {
69  return (int) round(max($this->memory_limit / 4, 8 * 1024));
70  }
71 
79  public function sendResponse(ResponseInterface $response): void
80  {
81  //check if the request is already send
82  if (headers_sent()) {
83  throw new ResponseSendingException("Response was already sent.");
84  }
85 
86  //set status code
87  http_response_code($response->getStatusCode());
88 
89  //render all headers
90  foreach (array_keys($response->getHeaders()) as $key) {
91  // See Mantis #37385.
92  if (strtolower($key) === 'set-cookie') {
93  foreach ($response->getHeader($key) as $header) {
94  header("$key: " . $header, false);
95  }
96  } else {
97  header("$key: " . $response->getHeaderLine($key));
98  }
99  }
100 
101  //rewind body stream
102  $stream = $response->getBody();
103  $stream->rewind();
104 
105  // check body size
106  $body_size = $stream->getSize();
107  if ($body_size > $this->memory_limit) {
108  $this->method = self::METHOD_READFILE;
109  }
110 
111  //detach psr-7 stream from resource
112  $resource = $stream->detach();
113 
114  $sendStatus = false;
115 
116  if (is_resource($resource)) {
117  set_time_limit(0);
118  try {
119  ob_end_clean(); // see https://mantis.ilias.de/view.php?id=32046
120  } catch (\Throwable) {
121  }
122  switch ($this->method) {
123  case self::METHOD_FPASSTHRU:
124  $sendStatus = fpassthru($resource);
125  break;
126  case self::METHOD_READFILE:
127  // more memory friendly than fpassthru
128  $sendStatus = true;
129  while (!feof($resource)) {
130  echo $return = fread($resource, $this->chunk_size);
131  $sendStatus = $sendStatus && $return !== false;
132 
133  }
134  break;
135  }
136 
137  //free up resources
138  fclose($resource);
139  }
140 
141  //check if the body was successfully send to the client
142  if ($sendStatus === false) {
143  throw new ResponseSendingException("Could not send body content to client.");
144  }
145  }
146 }
sendResponse(ResponseInterface $response)
Sends the rendered response to the client.
$response
Definition: xapitoken.php:93
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
header()
expected output: > ILIAS shows the rendered Component.
Definition: header.php:29