sso 综述

sso

理论文章 http://www.ibm.com/developerworks/cn/security/se-sso/index.html

这里面谈的cas的较多,另外一方面还有openID可以了解一下。

1. SSO 原理浅谈

这篇文章写的很好,特别要注意要保证      的安全。
http://kazge.com/archives/491.html

3. CAS 以外的其他开源 SSO 方案

           除了 CAS 之外,还有很多开源的 SSO 方案,采用何种方案跟用户的应用环境有比较大的关系。 SSO 的优劣一般要考虑易用性,安全性,性能,扩展性等因素。

3.1 JOSSO

           经常听到别人讨论 JOSSO , JOSSO ( www.josso.org )是我很早就用过的 SSO 开源项目,我后来抛弃了它,因为它存在比较多缺点,下面我们来看看:

1,  没有将后台认证与 SSO 分离,过分强调 JAAS , Axis 等

JOSSO 官方网站发布了 JOSSO 三个基准:

Standard Based

  • JOSSO security infrastructure is based on JAAS (Java Authentication and Authorization Service)
  • JOSSO uses web services implementing Axis as the distributed infrastructure.
  • JOSSO uses Struts and JSP standards

这些标准可以看到 JOSSO 的适应性存在较大的限制,因为 SSO 其实并不关心认证细节,作为一个开源项目,不应该引用过多的技术,如 Axis ,因为这个世界还有很多人用 Xfire 。

2,  没有描述 SSO 协议的 UseCase 图

从 JOSSO 的网站,似乎都看不到一个 SSO 的 UseCase ,容易让那些关注安全性的大型项目负责人感到忧虑。

3,  缺乏广泛的 SSO 客户端支持

JOSSO 的支持的客户端比较少,这个跟他的 Memember Team 、 Contributor Team 有比较大的关系。

4,  缺乏成功案例

读者使用任何 SSO 开源方案之前,有必要先了解次方案的成功案例, CAS 全球有 50 多个大学在使用 ( 大学对 SSO 的要求往往更复杂 ) 成功案例,这方面, JOSSO 跟 CAS 存在很大的差距。

5,  不支持跨域的落后设计

当然, JOSSO 不支持跨域是因为它使用了共享 cookie ,下面的话截取于 JOSSO 的官方文档:

JOSSO uses a session HTTP cookie to keep track of the SSO session identifier. This cookie lives as long as the browser window is open, being sent only in requests associated with the domain that generated it. This means that all JOSSO partner applications must be accessed using the same domain.

这段话给我们一个提示,如果设计 SSO 的时候,使用了 cookie 来在 SSO Server 和 SSO Agent( 相当于 CAS 的 CAS Client) 之间共享用户信息,那么这个协议是无法突破跨域限制的。因为当多个 SSO Agent 如果不使用同一个域名,也就是 Microsoft.com 和 IBM.com 无法共享同一个 cookie , JOSSO 采用了一种 DNS 技巧,即使用 Microsoft.sso.com 和 ibm.sso.com 来共享 cookie ,但这带来的问题同样很多,尤其是业务系统本身存在一些对域名限制的业务逻辑的时候,需要改动原来业务系统,这不是一件好受的事情。

3.2 CoSign

           CoSign 原先是 Michigan 大学的一个 SSO 项目, CoSign 是一个很不错的设计,但是它跟 CAS 比较相似,都是基于 Kerberos 方式的协议,一个最大的不同是 CoSign 的 SSO Server 是基于 CGI(Java Fans 更多会选择 CAS) ,对 C/C++ 的群体应该是一个不错的选择。 CoSign 协议的 UseCase 跟 CAS 很相似, CoSign 的客户端虽然也支持 J2EE/Apache/MSAPI(IIS) ,但它的 Server 端使用 C 来编写,影响了在 Java 群体中的使用。 CoSign 是一个不错的选择,可能是因为本人比较喜欢 Kerberos Model 的原因吧。

3.3 WebAuth

           WebAuth 是一种早期的 SSO 方案,它的 WebServer 是用 perl 来编写的,客户端支持 Apache , C++ , Perl 等,当然, WebAuth 推出的时候, Java 并不是很流行,现在,要让 WebAuth 跟众多的 Java 产品结合不是一件容易的事情。
WebAuth 的协议适用了 Share Secret ,即 SSO Server 和 SSO Client 之间存在一个对称密钥 (symmetric key ) 。 SSO Server 和 SSO Client 之间的信任关系通过这个 Key 来保障。
   上图中展示了一个 WebAuth 的基本模式, Client 就是浏览器用户, Generic Web Service 是 SSO Client , WebAuth Service 和 Auth Service 可以看作是 SSO Server 。
当浏览器发起一个对 Web 应用的访问请求时,这个请求未授权,因此被重定向到 WebAuth Service 进行认证,认证的结果是获得一个经过 symmetric key 加密的 token ,而这个 Token 只有 Generic Web Service 能够解密,因此, Web 应用能够知道浏览器用户的身份。使用对称加密来共享用户身份信息存在一定的安全隐患,首先是 WebAuth Service 如何保护这些对称密钥 ( 保护密钥安全本身是一件很困难的事情 ) ,一旦这些对称密钥被泄漏了, Token 就可以被随意篡改。另外,由于 Token 本身是基于 Cookie 方式发送,因此,只要 Hacker 能够复制这个 Token ,他同样可以访问其他应用。
如果不考虑安全性问题, WebAuth 的效率应该比其他 SSO 方案要高,因为它的协议没有 CAS/CoSign 那么复杂, WebAuth 中, SSO Server 不需要跟 SSO Client 通讯以确认用户的身份,用户的身份就放在 Token 中。

4. SAML

SAML 是 OASIS 制定的一种安全性断言标记语言,它用于在复杂的环境下交换用户的身份识别信息。在 SAML 诞生之前,如果想在 Websphere 、 Weblogic 和 SunONE 等之间实现 SSO ,我们必须分别实现一个适配层,来达成一种相互理解的协议,在该协议上,产品能够共享各自的用户认证 / 授权信息。 SAML 诞生之后,我们免去了这种烦恼。可以预计,将来大部分产品都可以实现基于 SAML 的联邦服务。
       事实伤, SAML 已经在很多商业 / 开源产品中得到实现,包括:

l         IBM Tivoli Access Manager

l         BEA Weblogic

l         Oblix NetPoint

l         SunONE Identity Server

l         Baltimore, SelectAccess

l         Entegrity Solutions AssureAccess

l         Internet2 OpenSAML

l         Yale CAS 3

l         Netegrity SiteMinder

l         Sigaba Secure Messaging Solutions

l         RSA Security ClearTrust

l         VeriSign Trust Integration Toolkit

l         Entrust GetAccess 7

SAML 背后是强大的商业联盟和开源联盟,尽管 Microsoft 迟迟未能在 SAML 2.0 观点上达成一致,但它也正努力跟进SAML标准化过程,由此可见SAML协议已经是势在必行。

4.1 SAML 的基本概念

           理解 SAML 的概念很重要,个人认为 SAML 协议的原理跟 CAS/Kerberos 很类似,理解上不存在困难,但 SAML 引入了一些新的概念名词,因此要先把握清楚这些概念。
       断言,这个在 SAML 的 ”A” ,是整个 SAML 协议中出现的最多的字眼,我们可以将断言看作是一种判断,并且我们相信这种判断,因此,做出断言的一方必须被信赖。校验来自断言方的断言必须通过一些手段,比如数字签名,以确保断言的确实来自断言方。
       SAML 目标是让多个应用间实现联邦身份 (Identity Federation) ,提起联邦,大家可以想象一下欧盟,欧盟国家之间的公民都具有一个联邦身份,比如 Peter 是法国公民, John 是比利时公民,这两个公民的身份都能够互相被共享,恰好,张三是一个中国公民,但他能像 Peter 和 Jhhn 那样随意进入欧盟国家,显然不能,因为它不具有欧盟联邦身份。
       理解了联邦的概念,我们就可以回到 SAML 上, SAML 解决了联邦环境中如何识别身份信息共享的标准化问题,比如,法国的 Peter 进入比利时,他如何证明自己的身份呢?
       SAML 就是为了解决这个问题。
在联邦环境中,通常有下面的 3 种实体:

l         Subject ( 主题 ) : Subject 是 SAML 实体中的第一个重要的概念, Subject 包括了 User 、 Entity 、 Workstation 等能够象征一个参与信息交换的实体。

l         Relying Party ( 信任方 ) : SAML 中的 Service Provider 角色,也就是提供服务的一方。

l         Asserting Party ( 断言方 ) : SAML 中的 Identity Provider 角色,用于提供对主题的身份信息的正确的断言,类似一个公证机构。

我们看看联邦环境的一个场景:
假设有一个 Peter(Subject) 的法国公民,他需要访问比利时 (Service Provider) ,他在比利时机场被要求提供身份信息, Peter 提供了欧盟 (Federation) 的通行证件,随即,这个通行证件在比利时机场被审核,或通过计算机送到欧盟身份认证中心 (Identity Provider) ,该中心有一个由所有欧盟国家共同建立的公民数据库,中心审核了 Peter 的身份信息,并断言“ Yes , He is Peter From France ”,于是, Peter 得到礼貌的回应“欢迎光临比利时”。
       如果你将欧盟看作是一个联邦环境,你会发现上面的场景跟在联邦环境应用 SAML 很相似。
在联邦环境下,任何需要授权访问的服务都需要知道服务请求方的身份主题信息 (Who are you) ,服务提供方 (Service Provider) 不负责审核用户的身份信息,但它依赖于 1 个甚至多个 Identity Provider 来完成此任务,见下图。
1 个 Idnetity Provider 可以被多个 Service Provider 共享,当然,共享的前提是建立信任关系 ( 即 Service Provider 要信任 Idnetity Provider) ,就好比如,如果比利时 (Service Provider) 需要开放对欧盟国家成员访问,它信任欧盟的 Idnetity Provider ,它信任欧盟的 Idnetity Provider 的任何判断,包括 ”He is Peter From France” 。至于是否让 Peter 入境,那是受权限策略的控制 ( 注意 SAML 同样对 Authorization 断言做了标准化,此处,我们仅仅关注 Authentication) 。

4.2 SAML 的 2 种典型模式

           在协议的角度, SAML 原理非常类似 CAS 和 Kerberos , CAS 协议依赖于 CAS Server , Kerberos 依赖于 KDC ,而 SAML 则依赖于 Identity Provider 。
       根据 Service Provider( 以下简称 SP) 和 Identity Provider( 以下简称 IDP) 的交互方式, SAML 可以分为以下几种模式:一种是 SP 拉方式,一种是 IDP 推方式。
       在 SAML 中,最重要的环节是 SP 如何获取对 Subject 的断言, SP 拉方式是 SP 主动到 IDP 去了解 Subject 的身份断言,而 IDP 推方式则是 IDP 主动把 Subject 的身份断言通过某种途径告诉 SP 。
2.2.1 SAML 的 POST/Artifact Bindings 方式(即 SP 拉方式)
       该方式的主要特点是, SP 获得客户端的凭证 ( 是 IDP 对 Subject 的一种身份认可 ) 之后,主动请求 IDP 对 Subject 的凭证的断言。如下图所示: Subject 是根据凭证去访问 SP 的。凭证代表了 Subject 的身份,它类似于“来自 IDP 证明:我就是 Peter ,法国公民”。
现在,让我们看看 SP 拉方式是如何进行的:  
Subject 访问 SP 的受保护资源, SP 发现 Subject 的请求中没有包含任何的授权信息,于是它重定向用户访问 IDP.
       协议执行:

1,  Subject 向 IDP 请求凭证 ( 方式是提交用户名 / 密码 )

2,  IDP 通过验证 Subject 提供的信息,来确定是否提供凭证给 Subject

3,  假如 Subject 的验证信息正确,他将获取 IDP 的凭证以及将服务请求同时提交给 SP 。

4,  SP 接受到 Subject 的凭证,它是提供服务之前必须验证次凭证,于是,它产生了一个 SAML 请求,要求 IDP 对凭证断言

5,  凭证是 IDP 产生的,它当然知道凭证的内容,于是它回应一个 SAML 断言给 SP

6,  SP 信任 IDP 的 SAML 断言,它会根据断言结果确定是否为 Subject 提供服务。

4.2.1 SAML 的 Redirect/POST Bindings 方式 ( 即 IDP 推方式 )
       该方式的主要特点是, IDP 交给 Subject 的不是凭证,而是断言。
       过程如下图所示:
       1 , Subject 访问 SP 的授权服务, SP 重定向 Subject 到 IDP 获取断言。
       2 , IDP 会要求 Subject 提供能够证明它自己身份的手段 (Password , X.509 证书等 )
       3 , Subject 向 IDP 提供了自己的帐号密码。
       4 , IDP 验证密码之后,会重订向 Subject 到原来的 SP 。
       5 , SP 校验 IDP 的断言 ( 注意, IDP 会对自己的断言签名, SP 信任 IDP 的证书,因此,通过校验签名,能够确信从 Subject 过来的断言确实来自 IDP 的断言 ) 。
       6 ,如果签名正确, SP 将向 Subject 提供该服务。

4.3 SAML 的优势所在

           SAML 协议仍在不断的发展, SAML1.0, SAML1.1 到现在的 SAML2.0 ,都是 IT 商业巨头协商后,由 OASIS 发布的产物,另外, OASIS SAML 实验室得到拥有美国政府 GSA 的大力资助。
SAML 在 SOA 中扮演了一个关键角色,由于用户要求将企业资源从原有的面向数据 / 接口转变为面向服务,而建立在众多 Vendor 产品下的服务存在这种种鸿沟,最大的鸿沟是如何识别身份,如何能够让网易 163 邮件的 VIP 用户享受免费参加 Dev2dev 广州 UserGroup 的活动?
读者可能已经听闻很多身份管理软件, IBM Tivoli , SiteMinder , RSA SecureID 等,虽然身份管理软件都非常强,但成本同时也很高。身份管理并不适合于那种构建是 B2B 之上的商业环境(联邦环境)。
但对用户来说,根本问题是,网易和 Dev2dev 是两个不同的公司 / 组织,它们都严格保护自己的用户身份信息,一般极少可能会共享身份数据,因此,做法是双方都提供一个服务入口,对身份信息做断言,例如只告诉 Dev2dev 该用户确实是网易的 VIP 用户。
SAML 提供了一个安全标记规范,并且给出了一些的 UseCase ,这些 usecase 足以满足我们绝大部分的 SSO 需求。
我喜欢这种规范,很大原因是因为以前用 SSO 实在很累,配置要花去大半天时间, SAML 让这一切变得非常灵活简单,因为厂商一旦在其产品中提供 SAML 支持,我们就可以将其产品作为联邦服务纳入 SSO 环境。
我喜欢 SAML 的另一个原因是因为,它跟 SOAP 一样,不考虑传输协议,事实上, SAML 可以跟 HTTP/SSL/JMS 等任何传输协议捆绑。在 SOA 环境中,这个特性非常重要,因为我们已有的许多服务(来自各个不同 IT Vendors )都可能有各自的传输协议,即如果在这种复杂的环境下实现 SSO ,传统 Yale CAS 已经无能为力,因为 CAS SSO 实现在 HTTP/SSL 之上,只有 SAML 能够完成这项任务,因为它与传输协议无关。
最后,应该提一下, SAML 是一种 SSO 标准而 CAS 是一种 SSO 的实现,从 CAS 的 Roadmap 可以看出, CAS 很快会提供对其他 SAML 的支持。
===============================================================================================================================================================================
Portal的功能可以分为三个主要方面:
1.        Portlet容器:Portlet容器与servlet容器非常类似,所有的 portlet都部署在portlet容器里,portlet容器控制portlet的生命周期并为其提供必要的资源和环境信息。Portlet容器负责初始化和销毁portlets,向portlets传送用户请求并合成响应。
2.        内容聚集:Portlet规范中规定portal的主要工作之一是聚集由各种portlet应用生成的内容,我们将在“如何创建Portal页面”部分对此做进一步讨论。
3.        公共服务:portlet服务器的一个强项是它所提供的一套公共服务。这些服务并不是portlet规范所要求的,但portal的商业实现版本提供了丰富的公共服务以有别于它们的竞争者。在大部分实现中都有望找到的几个公共服务有:
         o 单次登录:只需登录portal服务器一次就可以访问所有其它的应用,这意味着你无需再分别登录每一个应用。例如一旦我登录了我的intranet网站,我就能访问mail应用、IM消息应用和其它的intranet应用,不必再分别登录这些应用。
Portal 服务器会为你分配一个通行证库。你只需要在mail应用里设定一次用户名和密码,这些信息将以加密的方式存储在通行证库中。在你已登录到 intranet网站并要访问mail应用的时候,portal服务器会从通行证库中读取你的通行证替你登录到mail服务器上。你对其它应用的访问也将照此处理。
          o 个性化:个性化服务的基本实现使用户能从两方面个性化她的页面:第一,用户可以根据她的自身喜好决定标题条的颜色和控制图标。第二,用户可以决定在她的页面上有哪些portlets。例如,如果我是个体育迷,我可能会用一个能提供我钟爱球队最新信息的 portlet来取代股票和新闻portlets。
       一些在个性化服务方面领先的商业实现版本允许你建立为用户显示什么样的应用所依据的标准(如收入和兴趣)。在这种情况下,可以设定一些像“对任何收入为X的用户显示馈赠商品的portlet”和“对任何收入为X的用户显示打折商品的portlet”这样的商业规则。

 

 

============================

jasig实战

 

Continue reading sso 综述

一个将目录或指定文件使用img2py进行处理的小程序

[Python学习]一个将目录或指定文件使用img2py进行处理的小程序

img2py 可以将图片文件存成文本文件,但它不支持多个文件处理,这特别在我的目录下有许多的文件,如果一个个处理的话,会非常麻烦。于是为了解决目录及支持多个文件的问题,我编写了下面的小程序,希望对你有用。

import wx.tools.img2py as img2py
import getopt
import sys
import os
import os.path

def usage():
    print """
%s [-d directory][-h] -o outputfile files
""" % sys.argv[0]
def main():
    if len(sys.argv) == 1:
        usage()
        sys.exit(1)
    try:
        opts, fileArgs = getopt.getopt(sys.argv[1:], "d:o:h")
    except getopt.GetoptError:
        usage()
        sys.exit(1)

    imagedir = ''
    outputfile = ''
    for opt, val in opts:
        if opt == "-h":
            usage()
            sys.exit(1)
        elif opt == "-d":
            imagedir = val
        elif opt == "-o":
            outputfile = val

    convert(outputfile, imagedir, fileArgs)

def isImageFile(filename):
    f, ext = os.path.splitext(filename)
    if os.path.isfile(filename) and ext.lower() in ('.gif', '.png', '.bmp', '.jpg', '.ico'):
        return True
    else:
        return False
def convert(outputfile, dir='', imagefiles=[]):
    files = []
    files.extend(imagefiles)
    if dir:
        f = [os.path.join(dir, x) for x in os.listdir(dir) if os.path.isfile(os.path.join(dir, x))]
        files.extend(f)
    files = list(set([x for x in files if isImageFile(x)]))
    for i, x in enumerate(files):
        name = os.path.splitext(os.path.basename(x))[0].lower()
        cmd =[]
        if i != 0:
            cmd.append('-a')
        cmd.append('-n')
        cmd.append(name.capitalize())
        cmd.append(x)
        cmd.append(outputfile)
        os.system("img2py %s" % " ".join(cmd))
if __name__ == '__main__':
    main()

我们在写gui程序的时候,经常会用到一些图标图片资 源,对此有几种解决办法,有人喜欢用zip模块将其打包,用的时候取出来,因为python读取zip文件也是很方便的,有人则干脆不打包,直接放在一个 子目录中,用的时候直接读取。而我则喜欢将其转换为.py文件,作为模块调用。

我在看wxPython程序的例程的时候,[encode_bitmaps.py]发现它的图片是从一个模块(.py文件)中调入的,于是很好奇,顺藤摸瓜,于是发现:

wxPython安装好之后,会在 wx\tools 目录下安装一些工具,其中名为img2py.py的工具。
这个工具可以很方便的将我们程序中所用到的图片或者图标资源转换成py文件,这样我们在需要使用这些图片资源的时候,只需要
import 这些扩展名为.py的模块文件即可

在命令行下输入img2py.py并回车,可以查看详细的帮助信息。而一般情况下,我们所要做的,只是将图片转换为.py文件

例如,我有一个ico文件,想用其作为我程序的托盘图标

那么我可以这样做

首先,将其转换为 .py 文件

img2py.py myicon.ico myicon.py

然后,在程序中导入这个模块

import myicon

最后,当我需要用它的时候,只需要:

icon = myicon.geticonIcon()

注意,如果你的myicon.py中没有geticonIcon()方法,只需要加入如下一行语句即可:

geticonIcon = icon.GetIcon

怎么样,是不是很方便?

在 wx\tools 目录下还有一些其他的工具,具体用法还有待大家发掘

--------------------------------------------------

目的:
        即为img2py的用处,img2py是将图像转为以py文件存储的程序,简化了程序过程中读文件的处理。
开发环境:eclipse+pydev插件
步骤:
1,在 eclipse工程中增加个含有main函数的模块,用来处理图片到py,代码如下:
'''
Created on 2009-6-16
@author: fengxuanshuo

This is a way to save the startup time when running img2py on lots of
files...

'''
import sys
from wx.tools import img2py

command_lines = [
                 "-a -F -n book   pictures/right_menu/222.png   ../main/images.py",
                 "-a -F -n boo   pictures/right_menu/111.png   ../main/images.py",
                 "-a -F -n ook_red   pictures/right_menu/000.png   ../main/images.py",
                 ]

if __name__ == '__main__':
    for line in command_lines:
        args = line.split()
        img2py.main(args)
其中command_lines为命令行执行内容,程序需要的图片都可以处理,而且目标文件可以有多个,名字自己取。
2,执行新增加的模块,就会发现 main目录多了个images.py文件。
3,更新eclipse pydev工程:pydev插件并没有常用的那个add file to project选项,不过有pydev->source format python files.
4,然后再原工程里面就可以用图片py文件了(可能有些版本,在生成py文件的时候不会加import相关库的语句,需要手动添加)
5,images.py 在wxpython demo 中的用法
定义全局变量 images: images =None
在app里面声明全局的images : globel images
import imgaes as i
images = i
其他py文件类似,这么做的好处在demo的注释里面说了,不罗嗦了,over

Continue reading 一个将目录或指定文件使用img2py进行处理的小程序

SQLite in PHP

(一) SQLite介绍
SQLite第一个Alpha版本诞生于2000年5月. 至今已经有4个年头了. 而在今年的5月SQLite也迎来了一个新的里程: SQLite 3.
下面是你访问SQLite官方网站: www.sqlite.org 时第一眼看到关于SQLite的特性.
1. ACID事务
2. 零配置 – 无需安装和管理配置
3. 储存在单一磁盘文件中的一个完整的数据库
4. 数据库文件可以在不同字节顺序的机器间自由的共享
5. 支持数据库大小至2TB
6. 足够小, 大致3万行C代码, 250K
7. 比一些流行的数据库在大部分普通数据库操作要快
8. 简单, 轻松的API
9. 包含TCL绑定, 同时通过Wrapper支持其他语言的绑定
10. 良好注释的源代码, 并且有着90%以上的测试覆盖率
11. 独立: 没有额外依赖
12. Source完全的Open, 你可以用于任何用途, 包括出售它
从代码架构图你可以轻松的看出, 是的, SQLite非常简单. 对, SQLite的设计思想就是简单:
1. 简单的管理
2. 简单的操作
3. 简单的在程序中使用它
4. 简单的维护和客制化
因 为简单所以它快速, 但虽然简单, 却仍非常可靠. 适合SQLite的应用场所有, 网站,嵌入式设备和应用, 应用程序文件格式, 代替特别的文件, 内部或临时数据库, 命令行数据集分析工具, 在演示或测试中代替企业级数据库, 数据库教学, 试验SQL语言扩展等. 但并不是所有都合适, 比如在使用Server/Client结构的时候,高负荷的网站,高并发等情况下并不建议使用SQLite.
本 文重点在于介绍SQLite在PHP中的应用, PHP作为Web应用中一个重要力量一直在不断的前进和发展. 在马上就要Release的PHP的第五个版本中, 不再将MySQL作为默认支持, 而转为将SQLite的扩展作为默认支持. 从某种程度上说MySQL的广泛应用有PHP的很大功劳. 虽然说PHP改变默认支持有MySQL的授权改变的原因, 但选择SQLite也是有原因的, 理由就在于上面所提到的那些特性. 其实MySQL从来就不是完全免费的, 你无法用于商业用途. 而SQLite是完全的open的.
(二) SQLite SQL
SQLite的SQL从很大程度上实现了ANSI SQL92标准. 特别的SQLite支持视图, 触发器, 事务, 支持嵌套SQL. 这些都会在下面应用的过程中讲到, 故这边先暂时放下, 而主要说说SQLite所不支持的一些SQL.
1. 不支持Exists, 虽然支持in(in是Exists的一种情况)
2. 不支持多数据库, 如: create table db1.table1 as select * from db2.table1;
3. 不支持存储过程
4. 不支持Alter View/Trigger/Table
5. 不支持Truncate, 在SQLite中Delete不带Where字句时和Truncate的效果是一样的.
6. 不支持Floor和Ceiling函数, 还有其他蛮多的函数
7. 没有Auto Increment(自增)字段, 但是SQLite其实是支持Auto Increment的, 即在将该字段设置为” INTEGER PRIMARY KEY”的时候.
8. 不支持If Exists
……
详细的SQL支持可以访问: http://www.sqlite.org/lang.htm
详细的不支持SQL可以访问: http://www.sqlite.org/cvstrac/wiki?p=UnsupportedSql
(三) SQLite的数据类型
首 先你会接触到一个让你惊讶的名词: Typelessness(无类型). 对! SQLite是无类型的. 这意味着你可以保存任何类型的数据到你所想要保存的任何表的任何列中, 无论这列声明的数据类型是什么(只有在一种情况下不是, 稍后解释). 对于SQLite来说对字段不指定类型是完全有效的. 如:
Create Table ex1(a, b, c);
诚然SQLite允许忽略数据类型, 但是仍然建议在你的Create Table语句中指定数据类型. 因为数据类型对于你和其他的程序员交流, 或者你准备换掉你的数据库引擎. SQLite支持常见的数据类型, 如:
CREATE TABLE ex2(
a VARCHAR(10),
b NVARCHAR(15),
c TEXT,
d INTEGER,
e FLOAT,
f BOOLEAN,
g CLOB,
h BLOB,
i TIMESTAMP,
j NUMERIC(10,5)
k VARYING CHARACTER (24),
l NATIONAL VARYING CHARACTER(16)
);
前面提到在某种情况下, SQLite的字段并不是无类型的. 即在字段类型为”Integer Primary Key”时.
(四) SQLite的Wrapper
由 于SQLite有别于其他数据库引擎的TCP/IP或RPC访问方式, 完全地是本地的操作, 从某种角度来说你可以说SQLite和MS的Access很相似, 但是更小更强大. 所谓Wrapper即使对SQLite提供的接口进行封装, 使其他语言可以访问, 使用SQLite.
SQLite本身是提供C和Tcl的接口的. 所以可以非常轻易的和PHP相结合. 除了PHP的Wrapper以外, 还有许多世界各地的程序员提供了各种语言的SQLite的接口封装, 如Python, C++, Java, .Net…… 所流行的语言基本都有.
(五) PHP的环境下使用SQLite
1. PHP下的安装
在 PHP5中, SQLite已作为默认支持的模块.在PHP4中你需要进行安装. 首先去http://pecl.php.net/package/SQLite 去下载到SQLite的扩展, 注意Windows下的版本需要去http://snaps.php.net/win32/PECL_STABLE/php_sqlite.dll 下载, 当然你也可以下载代码自己编译.事实上在linux下只需要使用命令: ‘pear install sqlite’就可以完成安装,而在Win下需要修改php.ini, 同样的使PHP4支持SQLite.
此时你已经无需再安装任何东西了, 而你也已经完全支持SQLite了, 一个简单, 快速, 可靠的数据库.
如果你需要一个管理软件, 那么你可以尝试使用SQLiteManager (www.sqlitemanager.org), 一个与PHPMyAdmin类似的针对SQLite的数据库管理系统.
该系统的界面大致如下:
2. 第一个使用SQLite的PHP程序.
我们创建一个叫binzy的数据库, 并创建一个叫Binzy的Table, 有2个字段, 分别是ID, Title. 而其中ID为INTEGER PRIMARY KEY, 即自增三主键. 并在其中插入了2条数据”Binzy”, “Jasmin”.
打开并显示数据:
if ($db = sqlite_open('../binzy.db', 0666, $sqliteerror))
{ // 打开
SQLite$result = sqlite_query($db,'select * from Binzy'); // 查询while($row = sqlite_fetch_array($result)) // 获得结果
{
print 'ID=>'.$row['MyID'].', Name=>'.$row['Name'].'
';
}
} else {die ($sqliteerror);}
结果如下,
接下来Insert一条记录, 其中我们会使用到SQLite的事务.
if ($db = sqlite_open('../binzy.db', 0666, $sqliteerror)) {
sqlite_query($db,'BEGIN TRANSACTION'); // 开始事务
if (@sqlite_query($db,'insert into Binzy (Name) values (\'Binzy&Jasmin\')'))
{
print 'Execute Successfully';
sqlite_query($db,'COMMIT TRANSACTION'); // 提交事务
}
else
{
print sqlite_error_string(sqlite_last_error($db));
sqlite_query($db,'ROLLBACK TRANSACTION'); // 回滚事务
}
} else {
die ($sqliteerror);
}
如果执行失败, 便会出现这样的画面,
成功则是这样的,
是的, 如果你已经熟悉使用PHP对MySQL之类的数据库进行操作, 那么SQLite几乎是一样的, 而且更为简洁.
3. 使用Pear::DB (PHP4中)
上 面的例子中我们是使用PHP的函数直接对SQLite进行访问, 这样的访问方式是不推荐使用的. 更好的方式是使用某种数据访问抽象层, 如Pear的DB. 下面是2中查询例子的重写. 使用某个数据访问抽象层会更方便更安全, 并且可以在需要进行数据库迁移的时候尽可能减小成本.
require_once('DB.php');
$dbh = DB::connect('sqlite://@localhost/../binzy.db?mode=0666'); // 打开
$dbh->setFetchMode(DB_FETCHMODE_ASSOC);
if (!DB::isError($dbh))
{
$result = $dbh->query('select * from Binzy'); // 查询
if (!DB::isError($result))
{
while($row = $result->fetchRow()) // 读取
{ print 'ID=>'.$row['MyID'].', Name=>'.$row['Name'].'
';
}
$dbh->disconnect();
}
else
{
print($dbh->message);
$dbh->disconnect();
}
}
else
{
print($dbh->message);
$dbh->disconnect();
}
4. 使用Creole (PHP5中)
Creole是由phpdb.org开发的面向PHP5的数据访问抽象层. 关于Creole可参考本期中的《Creole :新兴数据抽象层》.
Pear::DB并没有针对PHP5进行改变, 只是因为PHP5对PHP4良好的兼容性, 使得Pear::DB在PHP5下仍能很好的工作. 所以在你使用PHP5的时候推荐使用Creole.
require_once('creole/Creole.php');
$Connection = null;
try{
$Connection = Creole::getConnection('sqlite://@localhost/../binzy.db?mode=0644'); // 获得Connection
$rs = $Connection->executeQuery('select * from Binzy'); // Get ResultSet while($rs->next())
{
print 'ID=>'.$rs->getInt('myid').', Name=>'.$rs->getString('name').'
';
}
$Connection->close();
}
catch(SQLException $exception) // Catch Exception
{
$Connection->close();
print $exception->getMessage();
}
(六) 总结
随 着PHP5的即将到来, 给我们带来了许多新的语言特性, 使PHP更加适合于构建强大健壮的各类系统. 而随着PHP5一起走进PHP开发人员视线的SQLite则给我们带来了有别于MySQL的惊喜. 是的, 他简单却又强大, 稳定. 而在刚刚过去的六月底新版本的SQLite3已经Release了第一个测试版本, 不仅仅带来了新的文件结构, 也带来了许多新的特性.

Continue reading SQLite in PHP

[转]Windows中PHP4 PHP5共存之道(加入个人遇到的问题)

     

  • 题外话: 即使不是装两个PHP,对安装一个PHP也具有很高的参考价值,比网上介绍的安装方法要好。它不需要复制文件到其他地方,升级非常方便。
    在学习PHP过程中可能要同时用到PHP4和PHP5,网上也有不少关于二者共存的安装方法,大多是一个安装在IIS下,一个安装在Apache下。下面介绍一下本人的安装方法,自认为比较优化,而且非常方便升级。
    为了方便介绍,先介绍一下本人的安装环境:Windows XP Pro SP2,Apache 2.0.55和PHP4.4.1、PHP5.1.1,都安装在D:\(即D区上有以下文件夹d:\apache2、d:\php4、d:\php5),网卡配置两个IP地址192.168.0.2和192.168.0.3(至于如何配置多个IP地址,不是本文介绍重点)。下面以Apache的模块式安装方法为例进行介绍:(配置多个IP地址:很简单,记得在哪里修改IP地址么?下边点"高级"->"添加" 添加一个新的ip地址,不要与局域网其他IP冲突,添加子网掩码确认即可)
    1、安装配置Apache 2.0.55服务器。在同意许可协议后会有填写服务器信息的页面,本地调试,前面两个输入 localhost 。编辑httpd.conf 文件,分别定位到ServerName localhost:80和Listen 80,都在前面加#关闭其设置。
    2、准备PHP。分别解压下载的PHP压缩包(例如php-5.1.1-Win32.zip),放置到d:\php4和d:\php5。
    3、分别配置php.ini。因为有两个版本的PHP,所以要分别配置。分别复制一份php.ini-recommended后重命名为php.in,就放在原路径。
    题外话:过时方法要这样处理,复制php.ini文件至x:\winnt(x:\windows)或apache的安装文件夹,并且copy x: \php\php5ts.dll、php4ts.dll等dll文件到winnt(windows)、或winnt\system32或apache的安装文件夹下。本人强烈推荐你不要这么做,以后升级比较麻烦,下面将给出理由。(你可以试着将c:\Windows的php.ini文件剪贴到php4或者php5的目录下,这样升级的确方便)
    4、修改windows path变量。加入
    代码:

    d:\php4;d:\php5

    到path环境变量中,即告诉系统到哪里去查找php5ts.dll等动态链接库文件,所以我们也没有必要将这些dll文件复制到%windir%,所以升级PHP也方便很多,不用去一一删除原来那些文件。至于怎样修改path路径(path路径很简单,查找我的电脑环境变量,在系统变量里的path值中加入代码;d:\php4;d:\php5)
    5、分别修改php.ini。主要修改一下extension_dir和extension_dir。分别在php.ini中找到上面的变量,加入适当的路径。我是这样修改的,PHP4的php.ini中
    代码:

    extension_dir = "D:\php4\extensions\"


    代码:

    include_path = "d:\php4\pear;d:\php4\includes"

    PHP5的php.ini中
    代码:

    extension_dir = D:\php5\ext


    代码:

    include_path = "D:\php5\PEAR;D:\php5\"

    其实一般来说还需要修改php.ini中的其他不少参数值,例如文件上传临时路径、Session临时路径、邮件设置、扩展模块配置(PHP5中为了支持mysql要去掉以下代码中的;号)
    代码:

    ;extension=php_mysql.dll

    6、修改httpd.conf。在最后加入以下代码:
    代码:

    <IfDefine !php5>
    Listen 192.168.0.2:80
    LoadModule php4_module "d:/php4/sapi/php4apache2.dll"
    PHPiniDir "d:/php4/php.ini"
    </IfDefine>
    <IfDefine php5>
    Listen 192.168.0.3:80
    LoadModule php5_module "d:/php5/php5apache2.dll"
    PHPiniDir "d:/php5/php.ini"
    </IfDefine>

    (以上IfDefine的功能还有很多,还可以嵌套使用,查询apache2手册)
    AddType application/x-httpd-php .php .phtml .php3 .php4
    AddType application/x-httpd-php-source .phps

    适当解释一下:
    代码:

    PHPiniDir = "d:\php4"

    即告诉Apache在"d:\php4"路径中查找php.ini文件,这样我们就不必将php.ini复制到其他目录中去,很好地处理了两个php.ini的共存问题。IfDefine是Apache的指令,可以在Apache手册中查找。
    http.conf的其他的指令,比如 DirectoryIndex 和 AddDefaultCharset 请自己设置。
    7、创建PHP5的Apache服务。在命令行下执行以下命令:
    代码:

    apache -k install -D php5 -n Apache2-PHP5

    (这个不要只会加服务,还要知道如何删服务,否则服务的apache的项目会越来越多

    打开注册表编辑器 开始-运行,输入“Regedit”,确定。依次打开
    HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services注册表项。
    在里面查找你所卸载的服务,删除他就可以了)

    即在windows中创建了php5 运行参数名称为Apache2-PHP5的服务项,可以到 管理工具->服务中启动,也可以使用 Apache 2 自带的 Monitor Apache Servers 启动。可以只运行任意一个PHP,也可以同时运行。
    8、调试PHP。用以下地址调试PHP4
    代码:

    http://192.168.0.2

    用以下地址调试PHP5
    代码:

    http://192.168.0.3

    (具体安装时IP地址可自行设置)
    特别提示:因为修改了path路径,所以一定要重启系统方可生效。而且配置了php.ini或http.conf后一定要重启Apache方可生效

Continue reading [转]Windows中PHP4 PHP5共存之道(加入个人遇到的问题)

PHP windows下版本选择及其它安装问题

这个问题只会是你在windows开发时存在,linux下没这么个情况。
看了半天,大概了解了:
apache的mod_php+php的Thread Safe v6版本。
apache的mod_fcgid+php的None Thread Safe v6版本。[我认为这个比较接近linux环境,推荐这个,使用进程就不存在线程问题]
另外php Debug Pack是为调试php本身用的与php使用者调试器zonedebuger,xdebuger不同
php apache2安装指南
http://docs.php.net/manual/zh/install.windows.apache2.php
Windows下PHP的线程安全(Thread Safe)版本和非线程安全(None Thread Safe)版本的选择?
八月 6th, 2010 Posted by zsj4cn
今天又在本机装了一下apache+php,在下载php的时候发现windows版本已经不在php.net主站下面了,有了一个独立的子域名:windows.php.net。
还有,我以前没有发现php for windows还有Thread Safe版本和None Thread Safe本版,一时还不该盲目下载来用。
查阅了一下资料,总结一下:
windows+apache2.2+php5.3 在都默认安装的情况下,apache2.2用了mpm_winnt_module本身是多线 程,apache的mod_php方式相当于上面家属的ISAPI方式被调用,php本身是线程安全的,但是php下的第三方扩展就不一定了。在这种情况 下,php应该选Thread Safe的安装程序。
如果调整一下配置,我建议用apache的mod_fcgid+php的None Thread Safe版本。
扩展阅读:
http://www.juyo.org/juyo/original/php-Thread-Safe/
…先从字面意思上理解,None-Thread Safe就是非线程安全,在执行时不进行线程(thread)安全检查;Thread Safe就是线程安全,执行时会进行线程(thread)安全检查,以防止有新要求就启动新线程的 CGI 执行方式耗尽系统资源。
再来看PHP的两种执行方式:ISAPI和FastCGI。FastCGI执行方式是以单一线程来执行操作,所以不需要进行线程的安全检查,除去线程安全 检查的防护反而可以提高执行效率,所以,如果是以 FastCGI(无论搭配 IIS 6 或 IIS 7)执行 PHP ,都建议下载、执行 non-thread safe 的 PHP …。而线程安全检查正是为ISAPI方式的PHP准备的,因为有许多php模块都不是线程安全的,所以需要使用Thread Safe的PHP。
说到这里,大家应该知道应该如何选择哪个版本的PHP了。None-Thread Safe or Thread Safe,您会选择哪个?
http://blog.bluesky.cn/archives/472/php-thread-safe-and-non-thread-safe-version-of-the-distinction-between.html
… 从2000年10月20日发布的第一个Windows版的PHP3.0.17开始的都是线程安全的版本,这是由于与Linux/Unix系统是采用多进 程的工作方式不同的是Windows系统是采用多线程的工作方式。如果在IIS下以CGI方式运行PHP会非常慢,这是由于CGI模式是建立在多进程的基 础之上的,而非多线程。一般我们会把PHP配置成以ISAPI的方式来运行,ISAPI是多线程的方式,这样就快多了。但存在一个问题,很多常用的PHP 扩展是以Linux/Unix的多进程思想来开发的,这些扩展在ISAPI的方式运行时就会出错搞垮IIS。因此在IIS下CGI模式才是PHP运行的最 安全方式,但CGI模式对于每个HTTP请求都需要重新加载和卸载整个PHP环境,其消耗是巨大的。
为了兼顾IIS下PHP的效率和安全,微软给出了FastCGI的解决方案。FastCGI可以让PHP的进程重复利用而不是每一个新的请求就重开一个进 程。同时FastCGI也可以允许几个进程同时执行。这样既解决了CGI进程模式消耗太大的问题,又利用上了CGI进程模式不存在线程安全问题的优势。
因此,如果是使用ISAPI的方式来运行PHP就必须用Thread Safe(线程安全)的版本;而用FastCGI模式运行PHP的话就没有必要用线程安全检查了,用None Thread Safe(NTS,非线程安全)的版本能够更好的提高效率。
-------------------------------------------------------------------------------------------------------------------------

php非线程安全和线程安全版本有什么区别

php5.3 版本有线程安全和非线程安全两种二进制for windows,我不明白这两种有什么区别,从网上没找到合适的答案,我用apache2.2+php5.2,一开始用非线程安全的apache启动不起 来,后换成线程安全的就可以了,不明白其中的原因?下面是一些相关解释可以看看。
看到zend debuger有非线程安全的版本,才知道PHP推出了非线程安全的版本。而此前我对非线程安全一无所知:
另一篇文章好像说这个跟 FASTCGI有点关系。
这是一段文字,不过我没看明白:
php本身是线程安全的。一个服务进程可以安全地提供多请求线程的支持
一些扩展并不遵守
例如:线程安全的扩展中,全局变量的定义不是像普通C程序那样直接定义在函数之外,而是定义在宏 ZEND_BEGIN_MODULE_GLOBALS和 ZEND_END_MODULE_GLOBALS之间。需要ZTS(Zend Thread Safe)支持的扩展需要包含TSRM.h头文件,并定义TSRMG宏值
在不支持线程安全的扩展中,仅是简单地认为一个服务进程同时只有一个请求在激活状态,不会出现冲突,那么全局变量可以简单地在RINIT函数中初始化(RINIT表示请求开始)并在RSHUTDOWN中注销:
CODE:[Copy to clipboard]PHP_RINIT_FUNCTION(ext)
{
counter = 0;
}
PHP_FUNCTION(ext)
{
RETURN_LONG(counter++);
}
…这就是一个很简单的计数器。只要请求没有结束,每次调用ext,都会触发 counter自增。
当在多线程环境中时,这个程序会发生严重的混乱,counter会变得飘忽不定,因为没有办法预测线程的触发和结束顺序及时间。这说明这个扩展并非线程级安全。
多线程,Apache 1.3 和 Apache 2.0
如 果您已经使用了 Apache 和 PHP 一段时间了,那么您很可能见到过安装文档中的一个警告信息,它说“不要在生产环境中使用 Apache 2.0.x 和 PHP,在 Unix 和 Windows 上都不行”。在 Windows 系统上的 PHP 5.0.2 包中,这个警告信息可以在 install.txt 文件中的第 745 行找到。我们需要理解此处的这个问题是什么,这样就可以决定是否要使用 Apache 2.0 或 IBM HTTP Server 2.0。
Apache 2.0 可以配置为以两种方法运行:采用线程的和不采用线程的。当作为一个采用线程的服务器运行时,服务器中可以同时有多个线程都处于活动状态在执行,一次可以为 多个用户生成响应信息。通常,这样可以提高服务器的响应能力,使其更好地利用具有多个处理器的大型硬件。但是它同时也引入了一种风险。服务器调用的各个软 件层次必须在同时为多个用户调用时都能保证是安全的。尽管 Web 服务器本身、PHP 解释器以及 PHP 扩展以这样调用都是安全的,但是有些 PHP 扩展会使用其他语言(例如 C 语言)编写的库,这些库并不全都是线程安全的。
在 Apache Web 页面上您可以找到一个有关这个问题的讨论,其中给出了一些建议,以及一种用来发现您的 PHP 扩展可能正在使用哪些 C 库以及哪些是线程安全的方法,请参阅参考资料部分。
在 实践中,很多人都会选择回避这个问题,而是采用下面的两种方法:要么以单线程模式使用 Apache 2.0,要么使用 Apache 1.3,它总是以单线程模式运行。虽然 Apache 1.3 和 2.0 也有其他一些区别,例如 Apache 2.0 可以支持 IPv6,但是到目前为止,二者之间最大的区别就是线程的问题,因此保留使用 Apache 1.3 服务器并不像听起来一样是一种退化。
这 个问题在 IBM HTTP Server 中是怎样的呢?IBM 采用线程模式从 Apache 2.0 中编译出了 IBM HTTP Server:这样速度更快,但却可能在使用非线程安全的扩展时是不安全的。由于 IBM 并没有同时发行源代码,而且选择采用线程和不采用线程的模式都是在编译时进行选择的,因此作为一个终端用户来说,您无法选择采用不使用线程的模式重新编译 IBM HTTP Server 2.0。不过在编写本文时,IBM 正在同时发行基于 2.0 和 1.3 版本的 IBM HTTP Server,这样您就可以选择使用单线程的基于 1.3 版本的服务器了。
----------------------------------------------------------------------------------------------------------------------------
关于Apache的MPM【转自apache模块开发指南】
2010年03月16日 星期二 14:23

2.3.1 为什么需要MPM

老版本的NCSA server和Apache 1是在UNIX系统中成长起来的。当时Apache是一个多进程服务器,一个服务进程处理一个用户请求,如果当前并发客户访问数量大于服务进程 数,Apache便会增加新的服务进程来处理当前请求。在正常情况下,Apache会维护一定数量的服务进程来处理用户的请求。

尽管这种多进程服务机 制在Unix类系统中能够很好地工作,但是在其他的平台上效率却很低,如在Windows中产生一个进程是非常费时的。因此,让Apache真正实现跨平 台还需要其他的方法。Apache 2采用的方法是把核心任务处理作为一个可插拔的模块,即MPM,使其能针对不同的环境进行优化。MPM架构允许不同的Apache模块在一个操作系统平台 下共存,能够为用户根据不同应用做出选择。

在实际应用中,只 有UNIX类操作系统有其他的选择,而其他系统平台(Windows、Netware、OS/2、BeOS)则只有唯一的根据操作系统优化的MPM。在 UNIX平台上,Apache 2.2目前已经有两种高质量的、作为标准的MPM(Prefork和Worker),第三种(Eevent方式)在不使用SSL的情况下也是稳定可靠的。 另外还有一些MPM可以实验应用,暂时不适合产品应用。其他第三方的MPM模块也是可用的。

2.3.2 UNIX类的MPM模块

Prefork MPM基于非线程模型,和Apache 1.x版本中的MPM很相似。Prefork MPM在所有情况下都很安全,对运行非线程安全(non-thread-safe)模式的软件如PHP,它是唯一的安全选择。对于某些应用程序,包括在 Apache 1.3上非常流行的程序(如简单静态页面、CGI脚本等),Prefork MPM是最好的选择。
Worker MPM基于线程模式,具有内存消耗低(对繁忙的服务很重要)、扩展性在某些特定应用情况下比Prefork更好等优点。在稍后介绍SQL数据库支持和mod_dbd模块时我们会讨论其中一些内容。
以上两种稳定的MPM方式在非常繁忙的服务器应用下都有些不足。尽管 HTTP的Keepalive方式能减少TCP连接数量和网络负载,但是Keepalive需要和服务进程或者线程绑定,这就导致一个繁忙的服务器会耗光 所有的线程。Event MPM是解决这个问题的一种新模型,它把服务进程从连接中分离出来。在服务器处理速度很快,同时具有非常高的点击率时,可用的线程数量就是关键的资源限 制,此时Event MPM方式是最有效的。一个以Worker MPM方式工作的繁忙服务器能够承受每秒好几万次的访问量(例如在大型新闻服务站点的高峰时),而Event MPM可以用来处理更高负载。值得注意的是,Event MPM不能在安全HTTP(HTTPS)访问下工作。
还有一些针对UNIX系统的、处于实验中的MPM,在本书编写过程 中,它们在继续开发,有的可能已经实现了。Perchild MPM具有一个非常好的特性:以不用的用户ID为不同的虚拟主机运行Apache服务器。其他的一些MPM也提供类似的功能,包括第三方的Metux和 Peruser,以及mod_ruid(只支持Linux)。为了运行外部程序,还可选择fastcgi/mod_fcgid和suexec(CGI)。 作者对第三方的解决方案没有相应的了解,因此不能作出相应的评价。

2.3.3 MPM模块和操作系统

一言以蔽之:对应用程序来说,MPM方式很少见,应该忽略!

既然MPM内部机制不是应用程序接口的一部 分,Apache的应用开发者不需要知道MPM的细节。这里就简单带过。一些为应用开发者提供的最佳实践的基本规则(命名机制、编写安全线程、交叉进程安 全、代码重入)将会在第4章中简单介绍。这里主要介绍开发平台无关代码。事实上,有时应用程序的开发平台更要考虑MPM而不是操作系统。

有时一个应用程序更加适应于某个MPM。例如,数据库驱动或者 负载均衡应用程序得益于thread MPM方式的连接池(在本书稍后讨论)。反之,产生子进程(原始的CGI实现或者mod_ext_filter)在一个基于线程的程序中会产生巨大开销, 因此在Prefork MPM方式下工作得更好。然而,除非某些特殊限制,应用程序应该考虑如何适应在非首选的MPM下工作。

如果你想让Apache运行在现在还不支持Apache的操作系统上,那么首要的任务是在APR库中增加对目标平台的支持。APR库用来提供操作系统层的支持。一个定制的MPM不是必需的,但是它很可能比已有的MPM提供更好的性能。从Apache的角度出发,这

是一个系统编程的任务,因此它已经超出一本应用程序开发书籍的介绍范围。

Continue reading PHP windows下版本选择及其它安装问题

[转]PHP的require和include路径问题经验总结(被包含路径弄晕了的来看看

 

被PHP的include路径弄晕了。自己试验一通,总结如下。
定义A=包含文件  B=被A包含的文件  C=被B包含的文件
也就是说 A 包含 B, B包含C
A中有Php代码

  1. require '[B路径]'  //(这里的require可以换成require_once include) 

require '[B路径]'  //(这里的require可以换成require_once include)
B中有
Php代码

  1. require '[C路径]'  //(这里的require可以换成require_once include) 

require '[C路径]'  //(这里的require可以换成require_once include)
下面的讨论主要针对A为入口文件,即只直接访问A,不直接访问B。
首先定义两个概念:相对路径和全路径,我对它们的定义是,相对路径指以.开头的路径,例如  ./a/a.php (相对当前目录)    ../common.inc.php (相对上级目录), 全路径是以/开头或者windows下的C:/类似的盘符开头的路径,全路径不用任何参考路径就可以唯一确定文件的最终地址。 例如      /apache/wwwroot/site/a/a.php c:/wwwroot/site/a/a.php
除了相对路径和全路径之外的路径还有其他类型的路径吗? 还有。凡是不以.或者/开头、也不是windows下盘符:/开头的路径,例如 a/a.php common.inc.php, 这样的路径,就是第三种类型路径。开始以为这也是相对路径,但在php的include/require包含机制中,这种类型的路径跟以.开头的相对路径 处理是完全不同的。 (require './a.php' 和 require 'a.php' 是不同的!)我们姑且叫这种路径为未确定路径
下面分析这三种类型包含路径的处理方式:首先记住一个结论:如果包含路径为相对路径或者全路径,则不会到include_path中去查找该文 件,也就是说不管php.ini中定义的include_path环境变量是多少,或者在程序中设置set_include_path(...)为多少。
引用
If a path is defined (full or relative), the include_path will be ignored altogether.
注意:下面的讨论和结论基于这样的环境:
假设 A=[SITE]/app/test/main.php, 再次强调下面的讨论是针对直接访问A的情况。 ([SITE]代表站点的根目录,可以替换成成http://www.xxx.com这样的域名根路径或者文档存储的物理目录如: c:/wwwroot/xxx.com 或者 /usr/wwwroot/xxx.com ),请读者在自己能测试的网站根目录创建/app/test/ 目录,并在其中创建main.php,最好是把下面的例子都实践一下。
1. 相对路径:
相对路径需要一个参考目录才能确定文件的最终路径,在包含解析中,这个参考目录是程序执行入口文件所在目录,不管包含嵌套多少层。
如果
A中定义  require './b/b.php';   //则B=[SITE]/app/test/b/b.php
B中定义  require './c.php';   //则C=[SITE]/app/test/c.php  不是 [SITE]/app/test/b/c.php
如果
A中定义  require './b/b.php';   //则B=[SITE]/app/test/b/b.php
B中定义  require '../c.php';   //则C=[SITE]/app/c.php  不是 [SITE]/app/test/c.php
如果
A中定义  require '../b.php';   //则B=[SITE]/app/b.php
B中定义  require '../c.php';   //则C=[SITE]/app/c.php  不是 [SITE]/c.php
如果
A中定义  require '../b.php';   //则B=[SITE]/app/b.php
B中定义  require './c/c.php';   //则C=[SITE]/app/test/c/c.php  不是 [SITE]/app/c/c.php
如果
A中定义  require '../inc/b.php';   //则B=[SITE]/app/inc/b.php
B中定义  require './c/c.php';   //则C还是=[SITE]/app/test/c/c.php  不是 [SITE]/app/inc/c/c.php
同理如果
A中定义  require '../inc/b.php';   //则B=[SITE]/app/inc/b.php
B中定义  require './c.php';   //则C=[SITE]/app/test/c.php  不是 [SITE]/app/inc/c.php
2. 全路径:
全路径的比较简单,不容易混淆出错。举一个简单例子
A中定义 require '/wwwroot/xxx.com/app/test/b.php';   //则在windows下B=c:/wwwroot/xxx.com/app/test/b.php (c:为服务器所在盘符),在linux下B=/wwwroot/xxx.com/app/test/b.php
dirname(__FILE__)计算出来的也是一个全路径形式的目录,但是要注意__FILE__是一个Magic constants,不管在什么时候都等于写这条语句的php文件所在的全路径,因此dirname(__FILE__)也总是指向写这条语句的php文件所在的全路径,跟这个文件是否被其他文件包含使用没有任何关系。
例如:
A中定义  require '../b.php';   //则B=[SITE]/app/b.php
B中定义  require dirname(__FILE__).'/c.php';   //则B=[SITE]/app/c.php
如果
A中定义  require '../inc/b.php';   //则B=[SITE]/app/inc/b.php
B中定义  require dirname(__FILE__).'/c.php';   //则B=[SITE]/app/inc/c.php 始终跟B在同一个目录
结论:不管B是被A包含使用,还是直接被访问,
B如果 require dirname(__FILE__).'/c.php' ,则始终引用到跟B在同一个目录中的 c.php文件;
B如果 require dirname(__FILE__).'/../c.php'  ,则始终引用到B文件所在目录的父目录中的 c.php文件;
B如果 require dirname(__FILE__).'/c/c.php'  ,则始终引用到B文件所在目录的c子目录中的 c.php文件;
3. 除相对路径和全路径之外的未确定路径
首先在逐一用include_path中定义的包含目录来拼接[未确定路径],找到存在的文件则包含成功退出,如果没有找到,则用写 require语句的php文件所在目录来拼接[未确定路径]组成的全路径去查找该文件,如果文件存在则包含成功退出,否则表示包含文件不存在,出错。
下面的讨论和结论需要首先在A文件的开头调用 set_include_path(dirname(__FILE__).'/../inc'); 设置include_path为 [SITE]/app/test/../inc 目录,其实就是 [SITE]/app/inc
并且在A中定义  require '../b.php';   //把B固定在[SITE]/app/b.php
这样如果
...未完...

Continue reading [转]PHP的require和include路径问题经验总结(被包含路径弄晕了的来看看

php开发环境配置

关于apache 和 fastcgi安装配置问题还是要看

apache的fastcgi文档,php的文档害人不浅,最终可以运行的配置如下:

在httpd.conf中要加入

LoadModule fcgid_module modules/mod_fcgid.so

<Directory "C:/me/php-wb/wb/">    #这里设置fastgid且不与之前配置冲突,比较好

AddHandler fcgid-script .php  //setHanlder即把所有处理都指向了fcgid,我查了半天,最后查AddHandler 才搞明白,这是基本问题,查都查不到。

FcgidWrapper "C:/Tools/php-5.3.3/php-cgi.exe" .php

Options execCGI #php文档就是没这一句搞得总是访问不了

AllowOverride None

Order allow,deny

Allow from all

</Directory>

另外开发时可配置

DocumentRoot "C:/me/php-wb/wb/"

也可在phpeclipse里面配置,如下图。

对于不适用zend框架的话,只有使用phpeclipse+xdebuger了

eclipse+phpeclipse开发配置如下图:可以不用xampp,配置好了apache和php后再在eclipse里面配置apache的启动

dffcd225_122grhh87wc_b

注意,先要检查是否安装apache服务实例

httpd -k install -n "Apache2.2"

不然不能停止,除非手动在管理器里面杀进程。

zend studio是基于pdt的,myeclipse 6.0安装pdt有问题,可能是eclipse版本太低。

索性直接下个zendstudio来算了.

关于debug 目前还是没配置好,网上也有人说到这个情况,不用debugger算了.

xdbug扩展是安装好了,但是eclipse 插件调试不了

可以看这篇文章 http://blog.sina.com.cn/s/blog_3d48dbb70100ueul.html

很是麻烦,不能像java tomcat中那样截取断点的调试。使用xdebug就是在出错时报错准确点!

zdebug扩展都没装好。

zend frame work安装只要在php.ini的include_path中包含zend下library目录即可,

这些配置可见其install.txt

php.ini的配置手册在php manual的附录中有

php manual还是看在线文档比较好,下载的怎么不讲php5,而且有错误。

Continue reading php开发环境配置

自定义struts2标签

网上有人指出基本步骤如下:
One of the developers recently mentioned they is writing a document about how to do this and I think there was talk about creating a maven archetype.
In the mean-time, try following some of existing code. The current version of the struts2 yui plugin provides a nice simple example as it only contains two tags and is packaged as a a plugin (http://code.google.com/p/struts2yuiplugin/source).【见附件:】
I find it's easiest to follow that example completely - use the maven plugin to generate the TLD and package your tags as a struts2 plugin. This isn't mandatory though as you can write the TLD by hand and include the classes in your webapp directly.
In general:
1. create a bean that extends UIBean or ClosingUIBean (for open & close tags), identifies the templates and populates the template context
2. create a tag class that extends AbstractUITag that creates the bean instance and sets the properties of the bean
3. create the templates referenced by the bean
After completing these 3 steps you can start using your tag if you write a TLD and include it in your classpath. If you copy the pom.xml from the example able you can use maven to generate the TLD (if you've used the appropriate annotations).
The remaining steps allowing your tags to be uses within freemarker and velocity templates (rather than only JSP)
4. Create a TagLibrary and TagModels for Freemarker and Directive's for velocity
5. Create struts-plugin.xml that declares your TagLibrary bean
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
plugin配置中:
<bean type="org.apache.struts2.views.TagLibrary" name="tagtest" class="test.s2.plugin.views.TestTagLibrary" />
freemarker models中:
    public AncorModel getAncor() {
        if (this.ancor == null) {
            this.ancor = new AncorModel(this.stack, this.req, this.res);
        }
        return this.ancor;
    }
那么应该这样使用:
<@tagtest.ancor ... />
注意前缀tagtest和后缀ancor分别对应蓝色斜体字。【shit!】
然而velocity的用法又不一样:
AbstractDirective:
    public String getName()
    {       
        return "testa" ;
    }
#testa (... )
这个与配置无关,是由getName返回的来决定的。

Continue reading 自定义struts2标签

strut2笔记

1:plugin-tiles在jdk1.4下面有问题,ServletContextListener重写一下可以解决问题。代码如下:(注意使用 RETROTRANSLATOR转换jdk5 编译的包时需要指明classpath="jdk1.4/rt.jar的路径")
https://issues.apache.org/struts/browse/WW-2897
package co.ntelagent.client.web.ps.application;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.tiles.ConfiguredServletContext;
import org.apache.struts2.tiles.StrutsTilesContainerFactory;
import org.apache.tiles.TilesContainer;
import org.apache.tiles.TilesException;
import org.apache.tiles.access.TilesAccess;
import org.apache.tiles.factory.TilesContainerFactory;
public class MyStrutsTilesListener implements ServletContextListener
{
    /**
     * Log instance.
     */
    protected static final Log LOG =
        LogFactory.getLog(MyStrutsTilesListener.class);
    private static final Map INIT;
    static
    {
        INIT = new HashMap();
        INIT.put(TilesContainerFactory.CONTAINER_FACTORY_INIT_PARAM,
                 StrutsTilesContainerFactory.class.getName());
    }
    /**
     * Initialize the TilesContainer and place it
     * into service.
     *
     * @param event The intercepted event.
     */
    public void contextInitialized(ServletContextEvent event)
    {
        ServletContext servletContext = event.getServletContext();
        try
        {
            TilesContainer container = createContainer(servletContext);
            TilesAccess.setContainer(servletContext, container);
        }
        catch (TilesException e)
        {
            throw new IllegalStateException("Unable to instantiate container.");
        }
    }
    /**
     * Remove the tiles container from service.
     *
     * @param event The intercepted event.
     */
    public void contextDestroyed(ServletContextEvent event) {
        ServletContext servletContext = event.getServletContext();
        try
        {
            TilesAccess.setContainer(servletContext, null);
        }
        catch (TilesException e) {
            LOG.warn("Unable to remove tiles container from service.");
        }
    }
    /**
     * Creates a Tiles container.
     *
     * @param context The servlet context to use.
     * @return The created container
     * @throws TilesException If something goes wrong during creation.
     */
    protected TilesContainer createContainer(ServletContext context)
        throws TilesException
        {
        if(context.getInitParameter(TilesContainerFactory.CONTEXT_FACTORY_INIT_PARAM) == null) {
            context = decorate(context);
        }
        else
        {
            LOG.warn("Tiles container factory is explicitly set.  Not injecting struts configuration.");
        }
        TilesContainerFactory factory =
            TilesContainerFactory.getFactory(context);
        return factory.createContainer(context);
    }
    protected ServletContext decorate(ServletContext context)
    {
        return new ConfiguredServletContext(context, INIT);
    }
}
2:plugin-tiles此时还不支持velocity视图,但支持freemarker(必须以ftl做扩展名)和jsp混用
3:action 配置后不需要明确指明method,使用时直接指向这个action,再指定method名称即可,调用时是只调用method方法。注意如果form指明了action,那么这个form的excute会执行,但是不会影响其内部元素的method的最终结果(而且会抛异常),这样不好,一般不要再 form上指明action

Continue reading strut2笔记

Pagination


Total views.

© 2013 - 2019. All rights reserved.

Powered by Hydejack v6.6.1