以前也曾经转载过关于BASE64方面的文章,那时候仅仅介绍了原理啥的。这回我找来的内容是如何实现的。。。
通过google找来了javaeye上的文章,他写了转载自xxx,进入xxx的页面,他告诉我转载自yyy每个人在转载的时候都去掉了一些内容。基于这样的现状,我。。。
不想转载了,贴出几个地址,自己看吧。
javaeye:http://chmod777.javaeye.com/blog/320301
xxx:http://www.cnblogs.com/yiki/archive/2009/01/18/1377828.html
yyy:http://www.cnblogs.com/reonlyrun/archive/2006/12/29/640991.html
这些实现在PHPer看来都是学习的经验,但phper根本不需要进行这些,因为php自带了base64_encode,base64_decode函数。
我要说的是,如何将加密的后的字符串在URL里传递,众所周知,base64中有三个特殊字符:"/,+,=",其中,=是补位码,/和+的标准字符,但/和=在URL里有着特定的意义,如果放到URL里,可能会被当成其他功能进行处理 。
于是,写了一个小函数进行了转换:
PHP代码
- function exchange ( $string , $reverse = false )
- {
- if ( $reverse === false ){
- return str_replace( array("/","+","="), array(":","|",";"), $string );
- }else{
- return str_replace( array(":","|",";"), array("/","+","="), $string );
- }
- }
其实功能很简单,无非就是把这三个有特殊意义的字符转换成在URL里不被解析的三个字符,只要不和base64所规定的字符相关,也不是URL处理中的特殊字符,这三个字符你可以替换成你平时喜欢用的字符。。。
这种方式有点另类,但确实是一种解决的方案之一。而且ob的方式还可以用来开启gzip。呵呵
原文地址:http://www.cnblogs.com/webnet/archive/2009/05/22/1486939.html
内容:
本文讨论的是如何彻底杜绝warning: Cannot add header information - headers already sent in...... 这种令人莫明其妙的的错误。
只要你写过PHP代码,相信都遇上过这个大多时候都令人莫明其妙的warning吧..今天我们就来搞定它...............
看了PHP手册,回答如下:
消息“Warning: Cannot send session cookie - headers already sent。。。”或者“Cannot add header information - headers already sent。。。”。
函数 header(),setcookie() 和 session 函数需要在输出流中增加头信息。但是头信息只能在其它任何输出内容之前发送。在使用这些函数前不能有任何(如 HTML)的输出。函数 headers_sent() 能够检查您的脚本是否已经发送了头信息。请参阅“输出控制函数”。
意思是:不要在使用上面的函数前有任何文字,空行,回车,空格等。但。。。问题是,这答案并不令人满意。因为往往程序在其他PHP环境下运行却正常。
首先:这错误是怎么产生的呢?让我们来看看PHP是如何处理HTTP header输出和主体输出的。
PHP脚本开始执行时,它可以同时发送header(标题)信息和主体信息。 Header信息(来自 header() 或 SetCookie() 函数)并不会立即发送,相反,它被保存到一个列表中。 这样就可以允许你修改标题信息,包括缺省的标题(例如 Content-Type 标题)。但是,一旦脚本发送了任何非标题的输出(例如,使用 HTML 或 print() 调用),那么PHP就必须先发送完所有的Header,然后终止 HTTP header。而后继续发送主体数据。从这时开始,任何添加或修改Header信息的试图都是不允许的,并会发送上述的错误消息之一。
好!那我们来解决它:
笨方法:把错误警告全不显示!
掩耳盗铃之计,具体方法就不说了 ^_^#
解决方案:
1)适用于有权限编辑PHP。INI的人
打开php。ini文件(你应试比我清楚你的php。ini在哪里),找到
output_buffering =改为on或者任何数字。如果是IIS6,请一定改为ON,不然你的PHP效率会奇慢。
2)使用虚拟主机,不能编辑PHP。INI,怎么办?
简单:
在你的空间根目录下建立一个。htaccess文件,内容如下:
AllowOverride All
PHP_FLAG output_buffering On
不幸的情况是:还是不行?全部网页都不能显示啦?
那么,你可以打电话骂一通空间商,然后让他给你把apache的。htaccess AllowOverride打开
3)在PHP文件里解决
ob_start()
启用output buffering机制。 Output buffering支持多层次 -- 例如,可以多次调用 ob_start() 函数。
ob_end_flush()
发送output buffer(输出缓冲)并禁用output buffering机制。
ob_end_clean()
清除output buffer但不发送,并禁用output buffering。
ob_get_contents()
将当前的output buffer返回成一个字符串。允许你处理脚本发出的任何输出。
原理:
output_buffering被启用时,在脚本发送输出时,PHP并不发送HTTP header。相反,它将此输出通过管道(pipe)输入到动态增加的缓存中(只能在PHP 4。0中使用,它具有中央化的输出机制)。你仍然可以修改/添加header,或者设置cookie,因为header实际上并没有发送。当全部脚本终止 时,PHP将自动发送HTTP header到浏览器,然后再发送输出缓冲中的内容。
原文基于.net,不过,我想PHP也差不多。而且这种问题很常见。。。
原文地址:http://www.cnblogs.com/flashlm/archive/2009/05/17/theSameNameCookie.html
内容:
了解Cookie的同学应该知道,浏览器客户端是以domain,path,name作为Cookie的唯一标识的,只要Name、Domain、Path中的任何一项不同,Cookie就是不能同的。由此便产生了同名Cookie。
例如有四个cookie如下:
d=1; expires=Sat, 23 May 2009 03:48:22 GMT; path=/; domain=.dny.com
d=2; expires=Sat, 23 May 2009 03:48:46 GMT; path=/; domain=.test.dny.com
d=3; expires=Sat, 23 May 2009 03:48:46 GMT; path=/test/; domain=.dny.com
d=4; expires=Sat, 23 May 2009 03:48:46 GMT; path=/test/; domain=.test.dny.com
他们是可以共存的。
了解Cookie的同学也应该知道,cookie的domain、path在服务器端都是只写的,也就是说在服务器端不能读取到任何一个Cookie的domain或者path值,只能读取到name和value。那么问题便产生了,假设上面的四个Cookie同时存在,那么服务器端读取到的name为“d”的cookie到底会是哪个值呢?
经过我的测试,结果是这样的,如果客户端浏览器发送了多个同名的 cookie,那么 Request.Cookie 将返回其中最符合(符合条件且范围最小)当前domain、path的一个。
例如,还是上面四个cookie,我通过下面这些地址去获取Request.Cookie["d“],值是不同的:
http://test.dny.com/test/cookies.aspx 4
http://dny.com/test/cookies.aspx 3
http://test.dny.com/cookies.aspx 2
http://dny.com/cookies.aspx 1
而实际上,服务器上用Request.Cookies.Count可以知道,得到的确实是有4个Cookie。
以上内容欢迎更加深入讨论。
--EOF--
我在想,由于客户端保存cookie是有长度限制的,象上面这四个COOKIE,如果在客户端保存的话,也应该是存为两个文件,一个是test.dny.com,一个是dny.com,那么path,又是怎么处理 的呢?偷懒,没做试验。。。。。。
以前一直都在转贴taobaoQA的关于测试类的文章,对于PHP来说,很少有人用到单元测试,毕竟PHP的调试确实很方便 。
但近年来,随着PHP越来越深入于做企业应用,因此对于单元测试的要求也就越来越被人放到台前。PHPUNIT都3.0了,想想看发展了多久了。
这是向东的博客上的一篇文章,不知道对各位有没有用,我是先复制下来看看。
1. 以各种借口拒绝单元测试Unit Test,比较常用的是“你没有足够的时间(进行单元测试)”。
2. 尝试单元测试并且立刻开始在自己的博客商鼓吹单元测试和测试驱动开发Test Driven Development的好处。
3. 单元测试一切。为了能够完成单元测试,而将私有private的方法和属性修改为内部internal;为了达到单元测试覆盖率100%而测试getter() 和 setter() 属性(方法)。
4. 无法忍受脆弱的单元测试,在没有弄明白是什么的时候,就匆忙转向“集成测试" integration test。
5. 发现了一种模拟 mocking 框架,并且乐于使用强制语义(strict semantics)。
6. 模拟mock所有可能模拟mocked的对象。
7. 开始真正有效单元测试。
你也可以参看如下文章:
http://www.xiangdong.org/blog/post/1665/
http://www.xiangdong.org/blog/post/1716/
http://www.xiangdong.org/blog/post/1354/
http://www.xiangdong.org/blog/visit.php?job=viewresult&sid=c642dcc3563a1ce54c5f3885b97b0105
原文在这里:http://www.xiangdong.org/blog/post/1768/
在数据库驱动的 Web 应用程序中实现 PHP5 对象的持久,朝着完全面向对象的 Web 应用程序开发迈进重要的一步。
许多开发人员都认同 PHP5 的面向对象实现的简洁和高效,并且同样被世界上最著名的数据库 — Oracle — 的强大功能和强健性所吸引。然而,从逻辑上更进一步 — 将 PHP 对象存储在数据库中以进行 Web 应用程序开发 — 可能将非常困难。
在这篇方法文档中,您将了解到如何通过一个(在 OracleDatabaseObject 程序包(下载)中提供的)对象持久层来存储和检索作为 Oracle 数据库中的对象的 PHP5 对象。利用这一技巧,任何 Oracle 开发人员都能够在他们的 Web 应用程序中最终实现完全面向对象 — 从而专注于应用程序逻辑,而不是麻烦的 SQL 和编码。
什么是对象持久层?
在解释如何在 Oracle 数据库中实现 PHP 对象的持久的机制之前,大家需要先了解支持它们的原理:对象持久层的概念。
世界上最受欢迎的脚本语言 PHP 只是在最近才为我们提供了面向对象的一个完整和合理的实现(在 PHP5 中)。这为希望效仿面向对象方法的严格性和灵活性的开发人员展现了一个激动人心的前景,面向对象方法在“传统的”编程环境中已经存在了很多年。然而,由于 关系数据库在 Web 的发展中扮演了如此关键的角色,希望充分利用这种方法的开发人员将面临一个的两难境地:对象技术明显不适合关系数据库技术。数据库需要表,而不是类;表需 要行,而不是对象。教科书上把这种现象称为“阻抗失谐”。
早于对象技术出现的关系数据库可以对作为简单类型集中在一起的简单数据进行适当地建模;例如,Person 表可以包含姓名 (varchar2)、身高 (INT) 和出生日期 (DATE) 列。相比而言,对象技术支持复杂数据类型的概念。例如,Person 对象可以包含 name 和 height 的基本类型,但也可以包含类型为 Person 的 partner、类型为 Job 的 job,每一种类型都有它们自己的复杂的数据结构。
因此,想收获面向对象方法的好处并存储复杂数据类型(PHP 对象)的 Web 开发人员只有两种选择:模拟或使用对象数据库,或者更可能的是,以专门的方式简单地存储数据对象。后一种做法(虽然很流行)是完全不可接受的,因为它抛弃 了面向对象的简洁性、可扩展性和可重用性,而这些是面向对象的主要好处。
幸运的是,Oracle 提供了对象类型、PL/SQL 和 REF。这些特性结合在一起形成了 Oracle 自己的面向对象实现;虽然这种实现从技术上看是不完整的,但它的确使开发人员能够容易地将对象存储为数据库对象,而不是以固定类型存储在表的行中。
然而,只是因为 PHP 和 Oracle “使用”对象技术并不意味着可以将 PHP 对象存储为 Oracle 对象(反之亦然)。因此,需要对象持久层服务来使 PHP 开发人员能够简单、高效地在 Oracle 数据库中存储和检索对象。
可以通过许多方式来执行这一操作,但所有方法都必须满足同样的需求:
- 必须通过简单、高效的服务来存储和检索对象。
- 存储在数据库中的对象必须能够包含对其他对象(复杂数据类型)的引用。
- 每一个对象必须有一个唯一的标识符。
- 当保存对象时,还必须能够保存所有其他相关的对象状态。
- 当检索对象时,还必须能够检索所有其他相关的对象状态。
OracleDatabaseObject 程序包是我对这些需求的实现。它反映了现有的最简洁的方法:使用抽象类和数据类型来对通用 的 Oracle 数据库对象建模。该方法允许任意类简单地继承这个通用类,从而继承持久所需的所有服务 — 实质上将其自身封装在一个可以和 Oracle 数据库接口的层中(参见下图)。

对象持久层将动态提供在数据库中实现对象持久所需的一切。无论何时当调用了方法 save() 来将 PHP5 对象存储到数据库中时,持久层的第一个任务是测试在此之前是否存储过这种类型的对象。如果没有,则将检查对象的状态(属性类型和值)。考虑以下对象:

如果在 Person1 上调用了 save() 方法,并且这是要保存在数据库中的第一个类型为 Person 的对象,那么将检查状态和它们的类型 — 在这种情况下,属性 Name、Age 和 Partner 分别有 PHP5 类型 String、Integer 和 Person。然后,要使这个对象能够持久,持久层将创建一个 Oracle 对象类型(也称为 Person),它的结构基于它对应的 PHP5 对象的状态。该层将在 Oracle 中复制 PHP5 类型 — Name (PHP5 string) 将变为 Oracle VARCHAR2;Age (PHP5 integer) 将变为 Oracle Number;PHP5 Partner(类型为 Person)将变为类型为 Person 的 Oracle REF。(关于这些转换的概述,请查看表 1。)
| PHP5 类型 |
Oracle 对象类型 |
| Numeric |
Number |
| String |
VARCHAR2 |
| Array |
VARCHAR2 * |
| Object |
Object |
| Associated Object |
REF to Object |
* 在撰写本文时,出于性能的目的,数组作为序列化的字符串以 VARCHAR2 类型存储在 Oracle 中。
然而,在未来,它们可能由 Oracle VARRAY 来实现。
一旦创建了 Oracle 对象类型结构来模拟它对应的 PHP5 类,属性值就将被保存到新创建的对象类型的表中。按照上述的第 4 点需求,当保存一个对象及其关联的对象时(如以上示例所示),还必须保存所有的关联关系。只需通过确保在检查和保存当前对象的内部状态时调用相关对象的 save() 方法来实现这一需求。
了解这些实现细节对于判断持久层具体在做些什么非常有用,但这种方法的强大之处在于您不需要了解这些。作为开发人员,您需要做的全部是利用交互对象来开发 和实现类 — 完全可以忽略所涉及的编程工作。利用这一层的服务,您可以在数据库中存储和检索对象,而永远无需设置表或处理 SQL,从而使您只需考虑应用程序自身的逻辑。
现在让我们看一个例子。
何时使对象持久
利用类和对象进行开发的实践是现在 PHP5 开发人员的日常工作。但并非所有这些对象都将在 Oracle 数据库中持久。因此,第一步是要决定是否需要为指定类的对象添加持久服务。
随着开发人员倾向于对 Web 全部使用面向对象,我们将共同创建并能够访问成千上万个类 — 但我们必须记住它们并非全部需要持久。相反,您必须考虑您的类代表了什么抽象概念,以及将如何在应用程序中使用类的对象。作为一条通用的基本原则:
如果在脚本完成之后必须存储对象的状态,并且在脚本运行时必须能够访问和/或更新对象的状态,那么就必须持久对象。
例如,大部分面向对象的 Web 开发人员会在应用程序中使用表单对象 — 但很少需要将它们存储在数据库中。例如,您不需要保存表单对象(包括其元素、目标、名称等),因为它在被创建之后就不会改变;所以无需在脚本中设置对象属 性并将它们存储在数据库中。相比而言,如果您在开发一个电子日历应用程序,那么您可能想使用条目对象作为每一天的对象,这种对象将在添加和编辑它们时改 变。当添加或修改了一个条目时,对象的状态也将改变;当一个条目变化时,您将把更新的版本保存在数据库中。
因此让我们利用这种应用程序的示例来浏览一下使用在下载(在撰写本文时提供了测试版本,计划在 2005 年底之前推出产品版本)中提供的 OracleDatabaseObject 程序包 (OracleDatabaseObject.class.php) 将持久服务添加到一个简单的 TestEntry 类 (TestEntry.class.php) 中的过程。
将 Oracle 数据库持久添加到类中
原始的 TestEntry 类如下所示:
PHP代码
- class TestEntry
- {
-
- public $title;
- public $body;
- public $author;
- public $dayName;
-
-
- function display()
- {
-
- Echo $this->title ."<BR>" .$this->body ."<BR>" .$this->author;
- }
-
- }
传统上将这个类的对象存储在 Oracle 数据库中将非常复杂。这个过程将包含创建一个与类的内部状态类似的表,然后利用关系 SQL 编写一系列的过程函数来插入/更新/删除类的各个属性。这是一个非常复杂、低效的任务 — 当对象变得更复杂时(可能包含数组或其他对象),它将变得几乎不可能完成。
OracleDatabaseObject 类使得您在其他方式下将手动完成的一切 — 例如存储类的内部状态(包括所有属性的类型)和创建 Oracle 对象类型 — 都变为动态完成,从而使得这个过程变得非常简单。最终的结果是您永远无需担心创建或修改 Oracle 数据库中的表或类型;您所需做的一切是专注于应用程序的逻辑。
因此,下面将创建 TestEntry 对象,并在数据库中存储和检索它们,让您的类继承 OracleDatabaseObject 类,该类已经内置了您所需的所有服务(参见表 2)。
表 2
| 方法 |
参数 |
目的 |
用途示例 |
| 对象 |
| save() |
无 |
将当前对象保存为数据库中的对象 |
$anObject->save() |
| load() |
无 |
利用当前的 objectName 从数据库中加载对象
|
$anObject->load() |
| 类 |
| addDatabaseUser ($username ) |
包含用户名的字符串,该字符串将用于存储类对象的数据库 |
- 为存储类的对象的 Oracle 服务器设置用户名、口令和数据库名称,使得能够利用各自的用户名和口令在各个数据库中存储类。
|
ClassName::setUserName(‘scott’) |
| addDatabasePass ($password) |
包含口令的字符串,该字符串将用于存储类对象的数据库 |
- ClassName::setPassword(‘tiger’)
-
-
-
|
| addDatabaseName ($databasename ) |
包含数据库名称的字符串,该字符串将用于存储类对象的数据库 |
ClassName::setDatabase(‘orcl’) |
将这些服务提供给 TestEntry 类的过程为:
PHP代码
- <?php
- include_once 'DatabaseObject.class.php';
- include_once 'OracleDatabaseObject.class.php';
-
- class TestEntry extends OracleDatabaseObject
- {
-
- public $title;
- public $body;
- public $author;
- public $dayName;
-
- function display()
- {
- echo $this->title ."<BR>" .$this->body ."<BR>" .$this->author;
- }
-
- }
下面您将通过使用 include_once 关键字(如第 1 行和第 2 行所示)来包含对您所需的类的访问权(OracleDatabaseObject 是一个继承 DatabaseObject 的抽象类)。然后可以使用 PHP5 继承关键字 extends(第 4 行)来继承 OracleDatabaseObject 类。继承的工作方式是获取父类的所有特性(方法)和属性(属性)并将它们提供给子类。这是一个简单但强大的想法(如下图所示):最初的 TestEntry 类继承 OracleDatabaseObject 类,产生一个结合了两者的特性的新的 TestEntry 类。

(左边显示的继承将产生右边显示的 Entry 类的一个新的版本。)
接下来,您将创建 TestEntry 类的对象,并使用服务层在 Oracle 数据库中保存和检索对象。
创建和使用 Oracle 持久对象
现在您的类拥有了所需的服务,将对象保存至数据库的过程将非常简单,如下所示 (ExampleA.php):
PHP代码
- <?php
- include_once "DatabaseObject.class.php";
- include_once "OracleDatabaseObject.class.php";
- include_once "TestEntry.class.php";
-
- TestEntry::addDatabaseUser('scott');
- TestEntry::addDatabasePass('tiger');
- TestEntry::addDatabaseName('orcl');
-
- $anEntry = new TestEntry();
- $anEntry->title = 'Meeting with boss - 9am';
- $anEntry->body = 'Meeting with boss scheduled to discuss raise';
- $anEntry->author = 'Joe Bloggs';
- $anEntry->dayName = 'Tuesday';
- $anEntry->objectName = 'Tuesday';
- $anEntry->display();
- $anEntry->save();
在继承 OracleDatabaseObject 之后,您必须通过使用表 2 中所示的服务来将用户名、口令和数据库名称与类绑定(如第 5-7 行所示的方式)。这个操作将使得能够通过单独的用户名、口令和数据库名称来获取各个类(从而获取该类的所有对象) — 顺便说一句,这将为您的对象提供非常细粒化的安全性。
不过,您可能希望为对象提供特定的名称,例如 Tuesday。这种方式将使您能够通过调用 load() 方法从数据库中快速容易地检索对象(如下面的 ExampleB.php 所示)。
您应当注意的最后但可能最重要的一件事是第 14 行中的方法 save()。这个方法也继承了 OracleDatabaseObject 类,它只是将对象保存到数据库中。
加载 Oracle 对象
您已经看到了在 Oracle 中保存对象有多容易。您甚至不需要接触数据库!自然,下一步是检索它 — 这将一样简单。
使用 ExampleB.php 示例,您将把数据库对象加载到一个新的 PHP5 对象中(如下所示):
PHP代码
- <?php
- include_once "DatabaseObject.class.php";
- include_once "OracleDatabaseObject.class.php";
- include_once "TestEntry.class.php";
-
- TestEntry::addDatabaseUser('scott');
- TestEntry::addDatabasePass('tiger');
- TestEntry::addDatabaseName('orcl');
-
- $anEntry = new TestEntry();
- $anEntry->objectName = "Tuesday";
- $anEntry->load();
- $anEntry->display();
这将产生和 ExampleA 相同的输出:只需从存储在数据库中的对象中重新加载对象的状态,无需任何复杂的调用和查询,并且只需通过调用 display() 方法来显示对象的状态。
SQL代码
- $sql = "SELECT * FROM:
- (
- SELECT
- r.*, ROWNUM as row_number
- FROM:
- ( $select ) r
- )
- WHERE row_number BETWEEN :start_row AND :end_row";
关于更广泛的演示,请查看提供下载的完整的示例电子日历应用程序。它包含了类的源代码以及 UML 图,从而使您能够更彻底地研究这一技巧。
使用 Oracle/PHP5 对象
将对象存储在数据库中不只是一个小花招;相反,它是满足“完全在面向对象范例中进行开发”的需求的最后一步。它使您能够无缝地使用在传统的大型面向对象编 程中流行的所有技巧 — 使用诸如业务对象、UML 和契约式设计等方法 — 来进行分析、设计、开发和测试。这是一种激进的想法,但 Web 开发领域正朝这个方向努力。
Barry McKay 是一个居住在苏格兰 Glasgow 的兼职 Web 开发人员和面向对象方法的拥护者。他还是 International PHP Magazine 的撰稿人。