title: PHP GeoServer Proxy Shape/Zip Request Returns Text
body: <h2>The Problem</h2>
  <p>Our GeoServer access is being proxied by a PHP script that handles the authorization/authentication. This works fine for WMS/WFS requests within an OpenLayers map, but not so much when trying to download a zipped-up shapefile the same way: the response ALWAYS returns the request as text.</p>
  <p>I know that my URL is correct, because when I take the prepped GeoServer URL and enter credentials manually, I get the desired &quot;Save As&quot; popup:</p>
  <p><a href="https://i.stack.imgur.com/ockkA.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ockkA.png" alt="FF Save Dialog" /></a></p>
  <p>When running it through the proxy, however, I get no dialog and a bunch of garbage:</p>
  <p><a href="https://i.stack.imgur.com/bl331.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/bl331.png" alt="enter image description here" /></a></p>
  <h2>The Solution Attempts</h2>
  <p>Most suggestions I've found point to:</p>
  <ul>
  <li><a href="http://php.net/manual/en/function.stream-context-create.php" rel="nofollow noreferrer"><code>stream_context_create</code></a></li>
  <li>Setting <a href="http://php.net/manual/en/function.header.php#refsect1-function.header-examples" rel="nofollow noreferrer"><code>Content-Disposition</code></a> in the header</li>
  <li><a href="http://php.net/manual/en/function.readfile.php" rel="nofollow noreferrer"><code>readfile</code></a></li>
  </ul>
  <h2>The Code</h2>
  <h3>URL Prep</h3>
  <p>Not sure if it matters, but here is how I am preparing the URL to send to GS (and that URL works fine sans proxy, manual credentials):</p>
  <pre><code>// Encode geoserver credentials
  $auth = base64_encode('username:password');
  
  // Base URL and parameters
  $url = 'https://example.com/mygeoserverpath/wfs?';
  $query = '';
  
  // Extract arguments
  $orig_proxy_url = $_SERVER['REQUEST_URI'];
  $orig_query = parse_url($orig_proxy_url, PHP_URL_QUERY);
  parse_str($orig_query, $orig_args);
  
  // Loop over arguments, append to base url
  foreach ($orig_args as $key =&gt; $value) {
      if ($key === 'cql_filter') {
          $value = rawurlencode($value);
      }
      $query = $query . '&amp;' . $key . '=' . $value;
  }
  
  $url = $url . $query;
  </code></pre>
  <h3>Using <code>stream_context_create</code> with Other Stuff</h3>
  <pre><code>$opts = array(
      'http' =&gt; array (
          'method' =&gt; &quot;GET&quot;,
          'header' =&gt; &quot;Authorization: Basic $auth&quot;
          . &quot;Content-Description: File Transfer\r\n&quot;
          . &quot;Content-Type: application/zip\r\n&quot;
          . &quot;Content-disposition: attachment; filename=testing.zip\r\n&quot;
      ));
  $ctx = stream_context_create($opts);
  </code></pre>
  <p>...in conjunction with some other attempts:</p>
  <pre><code>// file_get_contents returns text
  $output = file_get_contents($url,false,$ctx);
  
  // readfile returns text
  readfile($url,false,$ctx);    
  
  // fopen/passthru returns text
  $fp = fopen($url,'r',0,$ctx);
  fpassthru($fp);
  exit;
  </code></pre>
  <h3>Setting Headers Directly</h3>
  <p>I could get the Save dialog to appear this way, but it always was an empty zip.</p>
  <pre><code>header(&quot;Content-Description: File Transfer&quot;);
  header(&quot;Content-Type: application/zip&quot;);
  header(&quot;Content-disposition: attachment; filename=testing.zip&quot;);
  header(&quot;Authorization: Basic $auth&quot;);
  </code></pre>
  <h3><code>cURL</code></h3>
  <p>Not much to comment on here as I've been saving it as a very last resort.</p>
  <h2>Now What?</h2>
  <p>It shouldn't be this difficult considering GS does 99% of the work creating the zipped-up shapefile, but I'm running out of things to try. Any suggestions would be appreciated!</p>