Yii Framework appears to send headers in GET response - php

I have a piece of code that has stopped working as I am developing it (but has worked before) . It sends a few headers and then serves an image with readfile().
Here is my action:
public function actionShowMediaFile2() {
if (headers_sent()) {
...
In other words, the very first thing in my action is headers_sent() and this returns true.
Indeed, looking at the GET response in Firebug, there are several headers there. This prevents my sending my own headers and also seems to frustrate the readfile().
My questions:
1.- Does Yii Framework send headers autonomously?
2.- If so, how do I prevent this?
3.- Or is this perhaps not Yii-related?
Here are the headers that appear to be generated autonomously by Yii:
HTTP/1.1 200 OK
Date: Sun, 28 Oct 2012 10:59:05 GMT
Server: Apache
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 22
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/html
Checking with Fiddler, the server response appears to be: ���?�P�����k�[��� This is meaningless to me ...

Related

CORS AJAX-request fails even though the correct headers are specified

I am trying to send an AJAX-request from a page hosted on Github Pages (with https) to a php script hosted on a different domain (also https).
This is the code I am using in my AngularJS controller (although I don't think that is the problem):
$http.get('//thorin.epizy.com/cors.php?url=Place%2FGetClosestPlacesExtension%3Fcoordinates%3Dx%3D'+Math.round(vm.coords[0])+'%2Cy%3D'+Math.round(vm.coords[1])+'%26proposals%3D12').success(function (data) {
vm.success = true;
console.log('Recieved data from Ruter:',data);
});
The request fails and gives this error in the console:
When opening the Network panel in Chrome I see that the CORS headers are not present:
However, when I visit the page directly in the browser (typing the url into the url field) and open the Network panel all the correct headers are present:
I have tried sending the request from pages on other domains as well, bu I get the same error and no CORS headers. This makes very little sense to me and I have no idea how to fix it. I would really appreciate any help.
For a strange reason, thorin.epizy.com/cors.php doesn't send CORS headers without cookies:
curl -I 'http://thorin.epizy.com/cors.php?[...]' <other headers>
Date: Sun, 04 Dec 2016 16:42:57 GMT
Content-Type: text/html
Content-Length: 920
Connection: keep-alive
Vary: Accept-Encoding
Expires: Thu, 01 Jan 1970 00:00:01 GMT
Cache-Control: no-cache
With cookies, we get the correct headers:
curl -I -H 'Cookie: __test=b142b58439ba4f78e04c32cd1ba0a991' 'http://thorin.epizy.com/cors.php?[...]' <other headers>
HTTP/1.1 200 OK
Server: nginx
Date: Sun, 04 Dec 2016 16:45:04 GMT
Content-Type: application/json;charset=utf-8
Connection: keep-alive
Vary: Accept-Encoding
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS
Cache-Control: max-age=0
Expires: Sun, 04 Dec 2016 16:45:04 GMT
When you do a cross site request and want cookies, you need to ask for them with withCredentials (withCredentials: true with angularjs).
Then, the server will need to change two things:
add Access-Control-Allow-Credentials: true in the response
change Access-Control-Allow-Origin: * to Access-Control-Allow-Origin: your-web-site.com (usually taken from the Origin request header)
If you don't you will get the following message:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at ‘http://thorin.epizy.com/cors.php?url=[...]’. (Reason: Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’).

Transfer-Encoding: chunked sent twice (chunk size included in response body)

I'm using Apache 2.2 and PHP 7.0.1. I force chunked encoding with flush() like in this example:
<?php
header('HTTP/1.1 200 OK');
echo "hello";
flush();
echo "world";
die;
And I get unwanted characters at the beginning and end of the response:
HTTP/1.1 200 OK
Date: Fri, 09 Sep 2016 15:58:20 GMT
Server: Apache/2.2.15 (CentOS)
X-Powered-By: PHP/7.0.9
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
a
helloworld
0
The first one is the chunk size in hex (10 = A). I'm using Klein as PHP router and I have found that the problem comes up only when the HTTP status header is rewritten. I guess there is a problem with my Apache config, but I wasn't able to figure it out.
Edited: My problem had nothing to do with Apache but Nginx and chunked_transfer_encoding directive. Check the answer below.
This is how Transfer-Encoding: chunked works. The extra characters you're seeing are part of the encoding, rather than the body.
A client that understands the encoding will not include them in the result; a client that doesn't doesn't support HTTP/1.1, and should be considered bugged.
As #Joe pointed out before, that is the normal behavior when Chunked transfer enconding is enabled. My tests where not accurate because I was requesting Apache directly on the server. Actually, when I was experiencing the problem in Chrome I was querying a Nginx service as a proxy for Apache.
By running tcpdump I realized that Nginx was rechunking responses, but only when rewritting HTTP status header (header('HTTP/1.1 200 OK')) in PHP. The solution to sending Transfer-Encoding: chunked twice is to set chunked_transfer_encoding off in the location context of my Nginx .php handler.

Link between PHP and HTTP Request and Response Messages

When I did a networks course I learned about HTTP Request and Response messages and I know how to code in php reasonably enough to get around. Now my question is, the PHP has to have some link to HTTP request and response message but how. I can't seem to see the link between the two. My reasoning for asking this is that I am using the Twitter API console tool to query their api. The tool sends the following HTTP request:
GET /1.1/search/tweets.json?q=%40twitterapi HTTP/1.1
Authorization:
OAuth oauth_consumer_key="DC0se*******YdC8r4Smg",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1410970037",oauth_nonce="2453***055",oauth_version="1.0",oauth_token="796782156-ZhpFtSyPN5K3G**********088Z50Bo7aMWxkvgW",oauth_signature="Jes9MMAk**********CxsKm%2BCJs%3D"
Host:
api.twitter.com
X-Target-URI:
https://api.twitter.com
Connection:
Keep-Alive
and then I get a HTTP response:
HTTP/1.1 200 OK
x-frame-options:
SAMEORIGIN
content-type:
application/json;charset=utf-8
x-rate-limit-remaining:
177
last-modified:
Wed, 17 Sep 2014 16:07:17 GMT
status:
200 OK
date:
Wed, 17 Sep 2014 16:07:17 GMT
x-transaction:
491****a8cb3f7bd
pragma:
no-cache
cache-control:
no-cache, no-store, must-revalidate, pre-check=0, post-check=0
x-xss-protection:
1; mode=block
x-content-type-options:
nosniff
x-rate-limit-limit:
180
expires:
Tue, 31 Mar 1981 05:00:00 GMT
set-cookie:
lang=en
set-cookie:
guest_id=v1%3A14109******2451388; Domain=.twitter.com; Path=/; Expires=Fri, 16-Sep-2016 16:07:17 UTC
content-length:
59281
x-rate-limit-reset:
1410970526
server:
tfe_b
strict-transport-security:
max-age=631138519
x-access-level:
read-write-directmessages
So how do these HTTP request and response messages fit into PHP? Does PHP auto generate this? How do I add authorization to PHP requests etc? I'm confused about the deeper workings of PHP
When the client sends the HTTP request to the server, there has to be something to receive the HTTP request, which is called a web server. Examples of web servers are Apache, IIS, Nginx, etc. You can also write your own server, which can handle input however it wants. In this case, I'll assume that you are requesting a PHP file.
When the web server captures the HTTP request, it determines how it should be handled. If the file requested is tweets.json, it will go make sure that file exists, and then pass control over to PHP.
PHP then begins its execution, and performs any logic that the script needs to do, meaning it could go to the database, it reads, writes and makes decisions based cookies, it does math, etc.
When the PHP script is done, it will return a HTML page as well as a bunch of headers back to the web server that called it. From there, the web server turns the HTML page and headers back into a HTTP request to respond.
That is a pretty simple overview, and web servers can work in many different ways, but this is a simple example of how it could work in a introductory use-case. In more complex scenarios, people can write their own web servers, which perform more complex logic inside of the web server software, rather than passing it off to PHP.
When it comes down to it, PHP files are just scripts that the web server executes when they are called, they provide the HTTP request as input, and get a web page and headers as output.

How to get the "transfer-encoding" and "Content-Encoding" headers from external urls with PHP?

I have a client who would like to get a web-based report on all the headers from a webservice response. My client also uses SoapUI to check on method responses and he can double-check the response headers on that application.
I have tried PHP get_headers() and cURL methods and have gained access to most header parameters, however my client can also get the "transfer-encoding" and "content-encoding" parameters via SoapUI and my PHP requests do not get these.
My PHP get_headers result (same as cURL):
Cache-Control: private
Content-Length: 3037
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 2.0.50727
X-Powered-By: ASP.NET
Date: Wed, 18 Jul 2012 17:38:32 GMT
My client's SoapUI headers (I only pasted the ones that differ):
Content-Type: application/soap+xml; charset=utf-8
Vary: Accept-Encoding
Content-Encoding: gzip
Transfer-Encoding: chunked
It is very important for me to get the full set of headers - like SoapUI does - via PHP on our web-based application. My client wants to check if the responses are chunked and/or compressed via gzip. Am I missing another method to achieve such headers?

Where are these extra HTTP headers coming from?

When I simply echo something out of php file, I do not send any headers intentionally, however - there are some default headers present anyway when I look at firebug response:
response headers:
HTTP/1.1 200 OK
Server: nginx
Date: Thu, 23 Jun 2011 19:33:51 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/5.3.6-6~dotdeb.1
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Encoding: gzip
I'm curious - are these default response headers set by the server(nginx) or by PHP?
I believe it is a combination of both... You can tell that "X-Powered-By: PHP/5.3.6-6~dotdeb.1" comes from PHP and "Server: nginx" comes from NGINX.
You can alter the headers in PHP as follows:
<?php
header("HTTP/1.0 404 Not Found");
?>
The gzip header most definitely comes from NGINX as it is compressing the output (html) to the browser. PHP can "add" to the headers by calling a function like the one above. Then the server combines it with the PHP headers and serves the request.
It depends on your server whether or not the PHP headers take precedence over the server headers.
Hope this helps.
The majority are set by nginx, for example the Server, Date, Content-Encoding, and Connection. However, some other headers are set by PHP, and you can add others in PHP like this header("Name: Value");
The X-Powered-By header is controlled by the value of the expose_php directive in php.ini:
Decides whether PHP may expose the fact that it is installed on the server (e.g. by adding its signature to the Web server header). It is no security threat in any way, but it makes it possible to determine whether you use PHP on your server or not.
Most headers are sent by nginx. To list the headers (to be) sent by PHP, use the function headers_list:
<?php
echo htmlentities(print_R(headers_list(), true));
?>
PHP automatically sets some of them, like Content-Type: text/html for the hello world page. nginx sets the ones that have to do with the socket, like Connection: keep-alive.
You'll find settings for connections in nginx's configuration. Content-wise, it's PHP. You're allowed to override quite a few of them with the header() function in PHP, as well as add your own custom headers.
http://php.net/manual/en/function.header.php
For example, you could set the Content-Type to application/json if you're planning to have PHP send out a JSON string.
What's still missing in the answers is the role of PHP:
Some of the headers are indeed set by PHP itself, but the reason is not that easy to find. It's the default session cache delimiter behavior explained here: http://www.php.net/manual/en/function.session-cache-limiter.php
What's afaik not in the docs is how to turn them off completely - simply pass some undefined value to it:
session_cache_limiter(false);
You must to do this before you start your session. In case you are using the Zend Framework, you have to set this before your applications bootstrap() - otherwise it won't work.
You can also overwrite any of the default server headers using the header() function. For example, if you include in your PHP header('Server: ') this will reset the Server: header to be blank.

Categories