将代码从Windows传输到OS X时出现PHP问题

我最近买了一台新的MacBook Pro。 在我有我的MacBook Pro之前,我正在台式机上的一个网站上工作。 现在我想将这些代码转移到我的新MacBook Pro中。

问题是,当我转移代码(我把它放在Dropbox上,并简单地将它下载到我的MacBook Pro上),我开始在我的PHP代码中看到很多错误消息。

我收到的错误消息是:

警告:不能修改标题信息 – 第23行的/some/file.php中已经由(在/some/file.php:1开始的输出)发送的标题

我已经做了一些这方面的研究,似乎这个错误是最经常造成的一个新行,简单的空白或任何输出在<?php标志之前。 我已经查看了所有在HTTP请求中发送的cookie以及我使用header()函数的地方。 我没有检测到可能会干扰并导致此问题的任何输出或空白。

值得注意的是,错误总是说,输出是从第1行开始的。这让我想到,如果Mac OS X和Windows操作系统处理新行或空白的方式存在某种编码差异, 或者,Dropbox传输可能会搞砸了吗?

其中一个网站上的代码(login.php)产生错误:

  <?php include "mysql_database.php"; login(); $id = $_SESSION['Loggedin']; setcookie("login", $id, (time()+60*60*24*30)); header('Location: ' . $_SERVER['HTTP_REFERER']); ?> 

loginfunction:

 function login() { $connection = connecttodatabase(); $pass = ""; $user = ""; $query = ""; if (isset($_POST['user']) && $_POST['user'] != null) { $user = $_POST['user']; if (isset($_POST['pass']) && $_POST['pass'] != null) { $pass = md5($_POST['pass']); $query = "SELECT ID FROM Anvandare WHERE Nickname='$user' AND Password ='$pass'"; } } if ($query != "") { $id = $connection->query($query); $id = mysqli_fetch_assoc($id); $id = $id['ID']; $_SESSION['Loggedin'] = $id; } closeconnection($connection); } 

完整的错误:

 Warning: Cannot modify header information - headers already sent by (output started at /Users/name/GitHub/website/login.php:1) in /Users/namn/GitHub/website/login.php on line 9 

Solutions Collecting From Web of "将代码从Windows传输到OS X时出现PHP问题"

检查你的php开放标签前面是否有空格。 也可以尝试使用Windows(crlr)行尾从记事本++保存文件。 (编辑> EOL转换> Windows格式)

值得注意的是,错误总是说,输出是从第1行开始的。这让我想到,如果Mac OS X和Windows操作系统处理新行或空白的方式存在某种编码差异, 或者,Dropbox传输可能会搞砸了吗?

不要重做你的代码或担心header()调用,甚至cookie的东西。 这不是问题。

问题是Windows行结束与Mac行结尾不同。 更多细节在这里 。

不同的操作系统使用不同的字符来标记行结束符:

  • Unix / Linux / OS X使用LF(换行,'\ n',0x0A)
  • OS X之前的Mac使用CR(回车,'\ r',0x0D)
  • Windows / DOS使用CR + LF(回车后跟换行符'\ r \ n',0x0D0A)

在这种情况下,页面的格式会导致Apache中的PHP解析器阻塞文件。 在打算进行header()调用或设置cookie之前,可能将内容发送到浏览器。 在技​​术上意义上说,由于文件本身在不经意间将数据输出到浏览器,所以拧紧的行结束强制发送“标题”。

解决方案可能是避免使用Dropbox,只需将文件复制到闪存驱动器中,并以此方式进行传输。 这是一个想法,但我不相信Dropbox是在这个问题的罪魁祸首。 这意味着即使将文件复制到闪存驱动器,问题仍可能存在。

或者,如果这不起作用,做链接文章建议和下载一个像TextWrangler一个很好的文本编辑工具。 只需将文件加载到TextWrangler中,然后手动更改行结尾,使它们是Mac (CR)并重新保存文件。

这个问题的另一个长期解决方案可能是使用像git这样的版本控制系统与GitHub上的帐户相结合来管理你的代码。 好处是将代码推送到GitHub并从GitHub中提取代码,这个过程本身将处理跨平台的线程终结问题。 而且您不必担心由于将文件直接复制到DropBox等服务而造成的无意中造成的不必要的麻烦。

但是,相当确信这与Dropbox无关。 这一切都是关于Windows行结束与Mac OS X行结尾不同。

编辑:有一些有趣的想法,如何处理在Mac OS X提示的Windows行结束到Mac OS X行结束的批量转换。 最有意思的是使用zipunzip来促进这个过程。 我没有试过这个,所以要注意空格! 但是,从最后一行开始,它听起来像是值得测试的东西, 顺便说一句,这是“-a”标志解压缩,这导致ascii文件的行结束转换。

我一直使用以下(在一个名为fixascii的文件中):

 #!/bin/sh zip -qr foo.zip "$@" && unzip -aqo foo.zip && rm foo.zip 

然后执行它:

 fixascii [files or directories to convert] 

与其他大多数命令相比,这样做有好处,你可以在整个目录树中肆无忌惮地指向它,它将处理其中的所有文件,而不会破坏任何可能碰巧有一串比特的二进制文件像一条线结束。

当我试图用dos2unix或者tr结合find来修复文本文件的行结尾,但是却没有确保只有文本文件被处理的时候,我曾经见过有太多的时候有人破坏了大量的图像和其他二进制文件。 解压缩找出哪些文件是ascii,转换它们,并保留二进制文件。

顺便说一句,这是“-a”标志解压,这是导致ascii文件的行结束转换。

然后在官方手册页中查看-a (convert text files)选项下的unzip ; 重点是我的:

通常,所有的文件都是按照存储的(如“二进制”文件)提取的。 -a选项使得由zip标识的文件作为文本文件(在zipinfo列表中具有't'标签而不是'b')的文件被自动提取,转换行结束符,文件结束符和字符根据需要设置。 (例如,Unix文件使用行换行符(LF)作为行结束符(EOL),并且没有文件结束符(EOF)标记; Macintoshes使用回车符(Els)的回车符;大多数PC操作系统使用EOL的CR + LF和EOF的control-Z。此外,IBM大型机和密歇根终端系统使用EBCDIC而不是更常见的ASCII字符集,而NT支持Unicode。)请注意,zip的文本文件标识决不是完善; 一些“文本”文件实际上可能是二进制文件,反之亦然。 因此,使用-a选项时,将解压缩的每个文件打印为“[text]”或“[binary]”作为可视化检查。 -aa选项强制所有文件被提取为文本,而不管所假定的文件类型。

编辑:另外,如果您有权访问Linux机器,您可能需要签出dos2unix 。 更多细节在这里 。 并发现另一个堆栈溢出问题在这里 。

最后找到一个简单的方法来解决这个问题 当我遇到一个名为auto_detect_line_endings的选项时,我正在查看php.ini文件,并将其默认值设置为:Off。

这个选项的描述是:

 ; If your scripts have to deal with files from Macintosh systems, ; or you are running on a Mac and need to deal with files from ; unix or win32 systems, setting this flag will cause PHP to ; automatically detect the EOL character in those files so that ; fgets() and file() will work regardless of the source of the file. ; http://php.net/auto-detect-line-endings 

这正是我正在寻找的!

我简单地使用ini_set()函数在我的数据库文件(我加载每个PHP页面)的开始,它似乎已经解决了我的问题! 当脚本完成时,ini_set()函数还会将php.ini文件中更改的选项恢复正常。

我使用的ini_set()函数的完整行:

 ini_set("auto_detect_line_endings", true); 

谢谢你们的帮助!

ini_set()函数的更多信息在这里: ini_set()函数

有关auto_detect_line_endings选项的更多信息: 自动检测行结束选项