嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

周梦康 发表于 2014-04-01 2312 次浏览 标签 : PHP翻译

免费领取阿里云优惠券 我的直播 - 《PHP 进阶之路》

搞了四五个小时吧,加起来,肯定还是有很多错误。思前想后的,时在纠结。再加上很多高级功能自己不会用,就更加纠结啦。

<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision: $ -->
<!-- EN-Revision: 330342 Maintainer: 周梦康 Status: ready -->
<!-- Reviewed: no -->

<refentry xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://docbook.org/ns/docbook" xml:id="function.header">
 <refnamediv>
  <refname>header</refname>
  <refpurpose>发送一个自定义的http报文</refpurpose>
 </refnamediv>
 
 <refsect1 role="description">
  &reftitle.description;
  <methodsynopsis>
   <type>void</type><methodname>header</methodname>
   <methodparam><type>string</type><parameter>string</parameter></methodparam>
   <methodparam choice="opt"><type>bool</type><parameter>replace</parameter><initializer>true</initializer></methodparam>
   <methodparam choice="opt"><type>int</type><parameter>http_response_code</parameter></methodparam>
  </methodsynopsis>
  <para>
   <function>header</function> 被用来发送自定义的 <acronym>HTTP</acronym>
   报文。关于<acronym>HTTP</acronym>报文的更多信息请参考<link xlink:href="&url.rfc;2616">HTTP/1.1 specification</link>。
  </para>
  <para>
   请注意一点<function>header</function>必须在任何实际输出之前调用,不管是普通的html标签,还是文件里面的空行,空格或者是PHP文件里的空行,空格。这是一个非常普遍的错误,在通过<function>include</function>,<function>require</function>,或者其访问其他文件里面的函数的时候,如果在<function>header</function>被调用之前,其中有空格或者空行。如果不是调用其他文件,仅仅是单独使用一个PHP或者HTML文件,在<function>header</function>被调用之前有输出也会出错。
   <informalexample>
    <programlisting role="php">
<![CDATA[
<html>
<?php
/* This will give an error. Note the output
 * above, which is before the header() call */
header('Location: http://www.example.com/');
exit;
?>
]]>
    </programlisting>
   </informalexample>
  </para>
 </refsect1>

 <refsect1 role="parameters">
  &reftitle.parameters;
  <para>
   <variablelist>
    <varlistentry>
     <term><parameter>string</parameter></term>
     <listitem>
      <para>
       报文字符串。
      </para>
      <para>
       有两种特别的报文请求。第一种以“<literal>HTTP/</literal>”开头的 (case is not
       significant),将会被用来计算出将要发送的HTTP状态码。 例如你在Apache服务器上做了用一个PHP脚本来处理对不存在文件的请求(使用错误文档指令)的配置, 那么你在向服务器发送的报文请求的时候可能更希望你的脚本生成正确的状态码。
      </para>
      <para>
       <informalexample>
        <programlisting role="php">
<![CDATA[
<?php
header("HTTP/1.0 404 Not Found");
?>
]]>
        </programlisting>
       </informalexample>
      </para>
      <para>
       第二种特殊情况是“Location:”的头信息。它不仅把报文发送给浏览器,而且还将返回给浏览器一个<literal>重定向</literal>(302)的状态码,除非状态码已经事先被设置为了<literal>201</literal>或者<literal>3xx</literal>。
      </para>
      <para>
       <informalexample>
        <programlisting role="php">
<![CDATA[
<?php
header("Location: http://www.example.com/"); /* Redirect browser */

/* Make sure that code below does not get executed when we redirect. */
exit;
?>
]]>
        </programlisting>
       </informalexample>
      </para>
     </listitem>
    </varlistentry>
    <varlistentry>
     <term><parameter>replace</parameter></term>
     <listitem>
      <para>
       <parameter>replace</parameter>参数是可选参数,它表明否应该用后面一个相同类型的报文信息来取代前面一个相似的报文信息。默认情况下,是会发生取代的。但是如果你传入一个&false;,那么你可以强制使相同的报文信息并存。例如:
      </para>
      <para>
       <informalexample>
        <programlisting role="php">
<![CDATA[
<?php
header('WWW-Authenticate: Negotiate');
header('WWW-Authenticate: NTLM', false);
?>
]]>
        </programlisting>
       </informalexample>
      </para>
     </listitem>
    </varlistentry>
    <varlistentry>
     <term><parameter>http_response_code</parameter></term>
     <listitem>
      <para>
       强制指定HTTP响应的值。注意,这个参数只有在报文字符串(<parameter>string</parameter>)不为空的情况下才有效。
      </para>
     </listitem>
    </varlistentry>
   </variablelist>
  </para>
 </refsect1>

 <refsect1 role="returnvalues">
  &reftitle.returnvalues;
  <para>
   &return.void;
  </para>
 </refsect1>

 <refsect1 role="changelog">
  &reftitle.changelog;
  <para>
   <informaltable>
    <tgroup cols="2">
     <thead>
      <row>
       <entry>&Version;</entry>
       <entry>&Description;</entry>
      </row>
     </thead>
     <tbody>
      <row>
       <entry>4.4.2 and 5.1.2</entry>
       <entry>
        这个函数现在可以一次性阻止多个报文信息的发送,从而作为对报文信息注入攻击的一种防护。
       </entry>
      </row>
      <row>
       <entry>4.3.0</entry>
       <entry>
        增加了参数<parameter>http_response_code</parameter>。
       </entry>
      </row>
      <row>
       <entry>4.0.4</entry>
       <entry>
        增加了参数<parameter>replace</parameter>。
       </entry>
      </row>
     </tbody>
    </tgroup>
   </informaltable>
  </para>
 </refsect1>

 <refsect1 role="examples">
  &reftitle.examples;
  <para>
   <example>
    <title>下载对话框</title>
    <para>
     如果你想提醒用户去保存你发送的数据,例如保存一个生成的PDF文件。你可以使用<link
     xlink:href="&url.rfc;2183">Content-Disposition</link>的报文信息来提供一个推荐的文件名,并且强制浏览器显示一个文件下载的对话框。
    </para>
    <programlisting role="php">
<![CDATA[
<?php
// We'll be outputting a PDF
header('Content-type: application/pdf');

// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');

// The PDF source is in original.pdf
readfile('original.pdf');
?>
]]>
    </programlisting>
   </example>
  </para>
  <para>
   <example>
    <title>缓存指令</title>
    <para>
     PHP脚本总是会生成一些动态内容,而这些内容是不应该被缓存的,不管是客户端浏览器还是在服务器端和客户端浏览器之间的任何代理。我们可以像这样来强制设置浏览器和各个代理层不缓存数据:
    </para>
    <programlisting role="php">
<![CDATA[
<?php
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
?>
]]>
    </programlisting>
    <para>
     <note>
      <para>
       也许你会遇到这样的情况,那就是即使你没使用上面这段代码,你的页面也没有被缓存。大多数情况是因为用户可以自己设置他们的浏览器从而改变浏览器默认的缓存行为。一旦发送了上面这段报文信息,那么你就应该重写那些可能用到缓存了的代码。
      </para>
      <para>
       此外,在启用session的情况下,<function>session_cache_limiter</function>和<literal>session.cache_limiter</literal>的配置可以用来自动地生成正确的缓存相关的头信息。
      </para>
     </note>
    </para>
   </example>
  </para>
 </refsect1>

 <refsect1 role="notes">
  &reftitle.notes;
  &note.network.header.sapi;
  <note>
   <para>
    你所有需要输出到浏览器的数据将会一直缓存在服务器端,直到你发送他们,这将造成比较打开的资源开销。你可以是用输出缓冲来避开这个问题。你可以通过在脚本里使用<function>ob_start</function>和<function>ob_end_flush</function>或者直接在你的&php.ini;文件里设置<literal>output_buffering</literal>,也可以直接在服务器的配置文件里设置。
   </para>
  </note>
  <note>
   <para>
    HTTP状态信息的报文永远都是最新被发送到客户端的,而不管<function>header</function>是否是在最先发送的。报文状态码可能会被重写,当调用<function>header</function>来设定新的状态码,除非HTTP报文已经被发送了。
   </para>
  </note>
  <note>
   <para>
    在IE 4.01和IE 5.5里有bug,要解决就升级浏览器吧,想必也没人用那么远古的神器了吧。
   </para>
  </note>
  <note>
   <simpara>如果安全模式(<link linkend="ini.safe-mode">safe mode</link>)被激活,那么脚本的uid将会被添加到<literal>WWW-Authenticate</literal>的<literal>realm</literal>部分,前提是你设置了这个头信息的情况下(使用 HTTP 认证)。
   </simpara>
  </note>
  <note>
   <para>
    HTTP/1.1需要一个绝对的网络资源地址(<acronym>URI</acronym>)来作为一个参数供<link xlink:href="&spec.http1.1;-sec14.html#sec14.30">Location:</link>使用,在其中必须包含了协议,主机地址还有完整的路径,但是一些客户端可以接受相对的网络资源地址。你可以在一个相对的网路资源地址的基础上使用<varname>$_SERVER['HTTP_HOST']</varname>,<varname>$_SERVER['PHP_SELF']</varname>和<function>dirname</function>来组装一个绝对的网路资源地址。
    <informalexample>
     <programlisting role="php">
<![CDATA[
<?php
/* Redirect to a different page in the current directory that was requested */
$host  = $_SERVER['HTTP_HOST'];
$uri   = rtrim(dirname($_SERVER['PHP_SELF']), '/\\');
$extra = 'mypage.php';
header("Location: http://$host$uri/$extra");
exit;
?>
]]>
     </programlisting>
    </informalexample>
   </para>
  </note>
  <note>
   <para>
    在执行Location header跳转的时候,Session ID无法通传递的,即使<link
    linkend="ini.session.use-trans-sid">session.use_trans_sid</link>是激活状态的。只能通过手动传递using <constant>SID</constant>的值来实现。
   </para>
  </note>
 </refsect1>

 <refsect1 role="seealso">
  &reftitle.seealso;
  <para>
   <simplelist>
    <member><function>headers_sent</function></member>
    <member><function>setcookie</function></member>
    <member><function>http_response_code</function></member>
    <member>
     The section on <link linkend="features.http-auth">HTTP
     authentication</link>
    </member>
   </simplelist>
  </para>
 </refsect1>

</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->

嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

评论列表