分类归档 web开发

通过admin

Django日志logging的配置以及处理

      1. logging模块

logging模块为应用程序提供了灵活的手段记录事件、错误、警告和调试信息。对这些信息可以进行收集、筛选、写入文件、发送给系统日志等操作,甚至还可以通过网络发送给远程计算机。

> 日志记录级别

logging模块的重点在于生成和处理日志消息。每条消息由一些文本和指示其严重性的相关级别组成。级别包含符号名称和数字值。

级别 描述
CRITICAL 50 关键错误/消息
ERROR 40 错误
WARNING 30 警告消息
INFO 20 通知消息
DEBUG 10 调试
NOTSET 0 无级别

> 记录器

记录器负责管理日志消息的默认行为,包括日志记录级别、输出目标位置、消息格式以及其它基本细节。

 

关键字参数 描述
filename 将日志消息附加到指定文件名的文件
filemode 指定用于打开文件模式
format 用于生成日志消息的格式字符串
datefmt 用于输出日期和时间的格式字符串
level 设置记录器的级别
stream 提供打开的文件,用于把日志消息发送到文件。

>format 日志消息格式

 

格式 描述
%(name)s 记录器的名称
%(levelno)s 数字形式的日志记录级别
%(levelname)s 日志记录级别的文本名称
%(filename)s 执行日志记录调用的源文件的文件名称
%(pathname)s 执行日志记录调用的源文件的路径名称
%(funcName)s 执行日志记录调用的函数名称
%(module)s 执行日志记录调用的模块名称
%(lineno)s 执行日志记录调用的行号
%(created)s 执行日志记录的时间
%(asctime)s 日期和时间
%(msecs)s 毫秒部分
%(thread)d 线程ID
%(threadName)s 线程名称
%(process)d 进程ID
%(message)s 记录的消息

 

> 内置处理器

logging模块提供了一些处理器,可以通过各种方式处理日志消息。使用addHandler()方法将这些处理器添加给Logger对象。另外还可以为每个处理器配置它自己的筛选和级别。

handlers.DatagramHandler(host,port):发送日志消息给位于制定host和port上的UDP服务器。

handlers.FileHandler(filename):将日志消息写入文件filename。

handlers.HTTPHandler(host, url):使用HTTP的GET或POST方法将日志消息上传到一台HTTP 服务器。

handlers.RotatingFileHandler(filename):将日志消息写入文件filename。如果文件的大小超出maxBytes制定的值,那么它将被备份为filename1。

由于内置处理器还有很多,如果想更深入了解。可以查看官方手册。

 

2.django 使用logging记录日志

现在大概了解了logging的使用方法,现在可以结合django使用。

> 配置setting.py配置文件

 

#导入模块

import logging

import django.utils.log

import logging.handlers

 

 

LOGGING = {

‘version’: 1,

‘disable_existing_loggers’: True,

‘formatters’: {

‘standard’: {

‘format’: ‘%(asctime)s [%(threadName)s:%(thread)d] [%(name)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s’}  #日志格式

},

‘filters’: {

},

‘handlers’: {

‘mail_admins’: {

‘level’: ‘ERROR’,

‘class’: ‘django.utils.log.AdminEmailHandler’,

‘include_html’: True,

},

‘custom’: {

‘level’:’DEBUG’,

‘class’:’logging.handlers.RotatingFileHandler’,

‘filename’: os.path.join(BASE_DIR+’/logs/’,’all.log’),     #日志输出文件

‘maxBytes’: 1024*1024*5,                  #文件大小

‘backupCount’: 5,                         #备份份数

‘formatter’:’standard’,                   #使用哪种formatters日志格式

},

‘error’: {

‘level’:’ERROR’,

‘class’:’logging.handlers.RotatingFileHandler’,

‘filename’: os.path.join(BASE_DIR+’/logs/’,’all.log’),

‘maxBytes’:1024*1024*5,

‘backupCount’: 5,

‘formatter’:’standard’,

},

‘console’:{

‘level’: ‘DEBUG’,

‘class’: ‘logging.StreamHandler’,

‘formatter’: ‘standard’

},

‘request_handler’: {

‘level’:’DEBUG’,

‘class’:’logging.handlers.RotatingFileHandler’,

‘filename’: os.path.join(BASE_DIR+’/logs/’,’all.log’),

‘maxBytes’: 1024*1024*5,

‘backupCount’: 5,

‘formatter’:’standard’,

},

‘scprits_handler’: {

‘level’:’DEBUG’,

‘class’:’logging.handlers.RotatingFileHandler’,

‘filename’:os.path.join(BASE_DIR+’/logs/’,’all.log’),

‘maxBytes’: 1024*1024*5,

‘backupCount’: 5,

‘formatter’:’standard’,

}

},

‘loggers’: {

‘django’: {

‘handlers’: [‘default’, ‘console’],

‘level’: ‘DEBUG’,

‘propagate’: False

},

‘django.request’: {

‘handlers’: [‘request_handler’],

‘level’: ‘DEBUG’,

‘propagate’: False,

},

‘scripts’: {

‘handlers’: [‘scprits_handler’],

‘level’: ‘INFO’,

‘propagate’: False

},

‘views’: {

‘handlers’: [‘default’, ‘error’],

‘level’: ‘DEBUG’,

‘propagate’: True

},

}

}

 

 

解析:

1.formatters:配置打印日志格式

2.handler:用来定义具体处理日志的方式,可以定义多种,”default”就是默认方式,”console”就是打印到控制台方式。

3.loggers:用来配置用那种handlers来处理日志,比如你同时需要输出日志到文件、控制台。

 

注意:

1.loggers类型为”django”这将处理所有类型日志。

2.sourceDns.webdns.views 应用的py文件

 

> views.py代码配置

123

4

5

6

logger = logging.getLogger(‘sourceDns.webdns.views’)    #刚才在setting.py中配置的loggertry:

mysql= connectMysql(‘127.0.0.1’, ‘3306’, ‘david’)

except Exception,e:

logger.error(e)        #直接将错误写入到日志文件

>查看日志文件 ,可以用tail -f来跟踪log

[root@iZ94qyk9mopZ joke_project]# tail -f logs/all.log |grep jokes.views

2014-11-25 17:32:30,494 [Thread-3:140147426895616] [jokes.views:69] [views:get_jokes_list] [INFO]- get_jokes_list end
2014-11-25 17:37:32,987 [Thread-4:140147426895616] [jokes.views:37] [views:get_jokes_list] [INFO]- get_jokes_list start
2014-11-25 17:37:33,003 [Thread-4:140147426895616] [jokes.views:69] [views:get_jokes_list] [INFO]- get_jokes_list end

通过admin

python 变量命名规范

python源码和其他一些书籍,命名各种个性,没有一个比较统一的命名规范。于是自己总结了一些,可供参考。
模块名:
小写字母,单词之间用_分割
ad_stats.py

包名:
和模块名一样

类名:
单词首字母大写
AdStats
ConfigUtil

全局变量名(类变量,在java中相当于static变量):
大写字母,单词之间用_分割
NUMBER
COLOR_WRITE

普通变量:
小写字母,单词之间用_分割
this_is_a_var

实例变量:
以_开头,其他和普通变量一样
_price    
_instance_var

私有实例变量(外部访问会报错):
以__开头(2个下划线),其他和普通变量一样
__private_var

专有变量:
__开头,__结尾,一般为python的自有变量,不要以这种方式命名
__doc__
__class__

普通函数:
和普通变量一样:
get_name()
count_number()
ad_stat()

私有函数(外部访问会报错):
以__开头(2个下划线),其他和普通函数一样
__get_name()

通过admin

将Python的datetime转换为Unix时间戳timestamp

from datetime import datetime
d = datetime.utcnow()
import calendar
ts = calendar.timegm(d.utctimetuple())

用date命令来验证

$ date -ud @1382422118
2013年 10月 22日 星期二 06:08:38 UTC

在Unix系统上,描述时间的传统方式是,给一个自1970年初到现在的秒数.

from time import time
ts = int(time())
本文出自:http://zhiwei.li/text, 感谢原作者分享。
通过admin

Django mysql提交中文出错的问题

Django使用mysql的情况下默认编码都是utf-8,所以在一开始创建database的时候必须制定utf-8编码,否则在提交中文字符的时候可能会报错。

 

Creating your database

You can create your database using the command-line tools and this SQL:

CREATE DATABASE <dbname> CHARACTER SET utf8;

This ensures all tables and columns will use UTF-8 by default.

通过admin

Apache配置域名和多站点配置指引

配置Apache服务器并且设置DNS

我们通常所说的虚拟主机技术就是将一台(或者一组)服务器的资源(系统资源、网络带宽、存储空间等)按照一定的比例分割成若干台相对独立的“小主机”的技术。每一台这样的“小主机”在功能上都可以实现WWW、FTP、Mail等基本的Internet服务,就像使用独立的主机一样。phpma.com

 

目前网站服务器的虚拟主机平台使用以开放的Apache为最多,其次是微软的Windows IIS。Apache具有跨平台(FreeBSD/Linux/Windows/Solaris/Other UNIX)、易于维护与最佳安全性等优点。

Apache是率先支持基于IP虚拟主机的服务器之一。 Apache 1.1及其更新版本同时支持基于IP和基于主机名的虚拟主机,不同的虚拟主机有时会被称为基于主机(host-based) 或非IP虚拟主机(non-IP virtual hosts)。phpma.com

用Apache设置虚拟主机服务通常可以采用两种方案:基于IP地址的虚拟主机和基于主机名字的虚拟主机,下面我们分别介绍一下它们的实现方法以及优缺点。以便大家在具体的应用中能够选择最合适的实现方法。phpma.com

一、Apache实现基于IP地址的虚拟主机(每个站点拥有一个独立IP地址)

使用这种虚拟主机方式,首先要在服务器上为每个虚拟主机单独设置一个IP地址。这些IP地址可以通过增加多个网卡或者在一个网卡上设立多个IP地址来完成。有了多个IP地址后,可以采用以下两种方式之一来设置Apache。 phpma.com

1、为每个虚拟主机运行一份Apache

采用这种方式,每一份Apache程序可以以单独的用户运行,因此各个虚拟主机之间互不影响。设置这种虚拟主机时,只要为每一份Apache设置一套配置文件就可以了,唯一需要注意的是:必须使用“Listen”语句,强制每一份Apache 仅仅在属于“自己”的IP地址上接收服务请求。

优点:各个虚拟主机之间互不干扰,安全性高。

缺点:占用系统资源较多。

2、多个虚拟主机共享同一份Apache

采用这种方式,各个虚拟主机共享同一份Apache,因此各个虚拟主机之间有一定的影响,尤其是执行CGI程序时,可能会带来一些严重的安全问题。设置这种虚拟主机时,只要为每一个虚拟主机设置类似如下的信息即可:

<VirtualHost www.ghq1.com>

DocumentRoot /www/ghq1

</VirrualHost>

优点:占用系统资源比上一种方式少。

缺点:安全性低,每个虚拟主机仍然需要占用一个IP地址。

例如服务器一个网卡上绑定有两个IP地址(172.16.3.40和 172.16.3.50)分别对应域名 www.ghq1.com和www.ghq2.org的服务,配置如下

服务器配置(apache的配置文件httpd.conf)

Listen 80

<VirtualHost 172.16.3.40>

DocumentRoot /www/ghq1

ServerName www.ghq1.com

</VirtualHost>

<VirtualHost 172.16.3.50>

DocumentRoot /www/ghq2

ServerName www.ghq2.org

</VirtualHost>

配置简单说明:“Listen”默认httpd服务会监控第80号通信端口, “Listen”选项让用户自行指定apache 服务器监控的IP地址或通信端口。

“DocumentRoot”:指定apache 服务器存放网页的根目录;“ServerName”:允许用户自行设置主机名,这个名称将被送到远程连接程序,以取代安装apache 服务器主机的真实名称。<VirtualHost IP >和</VirtualHost>构成虚拟主机的语法结构,其中的IP就是我们在服务器上绑定的不同的IP地址,也可以是IP地址加上通信端口号(见下面的例子)。

如果服务器有两个IP地址(172.16.3.40和 172.16.3.50)分别对应域名 www.ghq1.com和www.ghq2.org。对每个域名,我们都希望在80端口和8080端口发布我们的网站。可以这样配置

服务器配置(apache的配置文件httpd.conf)

Listen 172.16.3.40:80

Listen 172.16.3.40:8080

Listen 172.16.3.50:80

Listen 172.16.3.50:8080

<VirtualHost 172.16.3.40:80>

DocumentRoot /www/ghq1-80

ServerName www.ghq1.com

</VirtualHost>

<VirtualHost 172.16.3.40:8080>

DocumentRoot /www/ghq1-8080

ServerName www.ghq1.com

</VirtualHost>

<VirtualHost 172.16.3.50:80>

DocumentRoot /www/ghq2-80

ServerName www.ghq1.orgphpma.com

</VirtualHost>

<VirtualHost 172.16.3.50:8080>

DocumentRoot /www/ghq2-8080

ServerName www.ghq2.org

</VirtualHost>

因此,建立虚拟主机,我们要做好不同的IP对应的域名解析工作,建立相应的目录(如/www/ghq1),将相应的主页内容存放在相应的目录中即可。

二、Apache实现基于主机名的虚拟主机服务(一个IP地址实现多个网站)

基于主机名字的虚拟主机服务,是目前虚拟主机比较常用的一种方案。因为它不需要更多的IP地址,无须什么特殊的软硬件支持。而且现在的浏览器大都支持这种虚拟主机的实现方法。基于域名的的虚拟主机是根据客户端提交的HTTP头中的关于主机名的部分决定的。使用这种技术,很多虚拟主机可以享用同一个IP地址。

基于域名的虚拟主机相对比较简单,因为我们只需要配置DNS服务器将每个主机名映射(CNAMES)到正确的IP地址,然后配置Apache HTTP服务器,令其辨识不同的主机名就可以了。基于域名的服务器也可以缓解IP地址(IPV4)不足的问题。这种方式下,各个虚拟主机共享同一份Apache,因此有CGI程序运行时,安全性也不高。

优点:只要一个IP地址就可以提供大量的虚拟主机服务。

缺点:安全性差。维护这些虚拟主机时需要更改配置文件,并且需要重新启动Apache进程才能起作用。因此不适合进行大规模的虚拟主机服务。

如果服务器只有一个IP地址,而在DNS中有很多映射到这个机器。我们想要在这个机器上运行www.ghq1.com和 www.ghq2.org两个站点。在Apache服务器的配置中创建一个虚拟主机并不会自动在DNS中对主机名做相应更新。我们必须自己在DNS中添加域名来指向我们的IP地址。否则别人是无法看到我们的web 站点。

服务器配置(apache的配置文件httpd.conf)

# Ensure that Apache listens on port 80phpma.com

Listen 80

# Listen for virtual host requests on all IP addresses

NameVirtualHost *

<VirtualHost *>

DocumentRoot /www/ghq1

ServerName www.ghq1.com

# Other directives here

</VirtualHost>

<VirtualHost *>

DocumentRoot /www/ghq2

ServerName www.ghq2.org

# Other directives here

</VirtualHost>

因为*(星号)匹配所有的地址,所以主服务器不接收任何请求。因为 www.ghq1.com首先出现在配置文件中,所以它拥有最高优先级,可以认为是默认或首要服务器。这意味着如果一个接受的请求不能与某个ServerName指令相匹配, 它将会由第一个VirtualHost所伺服。

当我们的IP地址无法确定的时候,使用*是很方便的–比如说, ISP给我们配置的是动态IP地址(如ADSL拨号上网),而我们有使用了某种动态域名解析系统时。因为*匹配任何IP 地址,所以在这样的情况下,不论IP地址如何变化,我们都不需要另外进行配置。上述配置就是我们在绝大多数情况下使用基于域名的虚拟主机时将要用到的。

本文档的涵义一言以蔽之就是:不要让Apache在解析配置文件的时候用到DNS。 如果Apache在解析配置文件时用到了DNS,您的服务器就会发生可靠性的问题(也可能根本无法启动), 或者遭致拒绝(偷窃)服务攻击(包括用户可以从其他用户那里偷窃点击)。

一个简单示例

拒绝服务

“main server”地址

避免这些问题的小技巧

附录:进一步的提示

一个简单示例

<VirtualHost www.abc.dom>

ServerAdmin webgirl@abc.dom 

DocumentRoot /www/abc 

</VirtualHost> webgirl@abc.dom 

DocumentRoot /www/abc 

</VirtualHost> webgirl@abc.dom 

DocumentRoot /www/abc 

</VirtualHost> webgirl@abc.dom 

  DocumentRoot /www/abc 

</VirtualHost> webguy@def.dom 

  DocumentRoot /www/def 

</VirtualHost> webmaster@host.foo.com

DocumentRoot /www/docs/host.foo.com

ServerName host.foo.com

ErrorLog logs/host.foo.com-error_log

TransferLog logs/host.foo.com-access_log

</VirtualHost> webmaster@host.foo.com

DocumentRoot /www/docs/host.foo.com

ServerName host.foo.com

ErrorLog logs/host.foo.com-error_log

TransferLog logs/host.foo.com-access_log

</VirtualHost>

为了让Apache功能正常,一个虚拟主机绝对需要以下两部分的信息: ServerName和与服务器对应的至少一个IP地址。 这个示例没有包括IP地址,于是Apache必须用DNS来查询www.abc.dom的地址。 如果在某些不可预料的情况下,当您的服务器解析配置文件时没有得到DNS的支持, 那么这个虚拟主机 将不会被配置。 它将不会对任何请求作出反应。(在Apache的1.2版本之前,服务器甚至无法启动)。

假设www.abc.dom的IP地址是10.0.0.1。那么看看以下这个配置片断

<VirtualHost 10.0.0.1>

ServerAdmin

现在Apache需要DNS对这个虚拟主机进行反向域名解析来确定ServerName。 如果反向解析失败,那么这将导致这个虚拟主机部分功能丧失。 (在Apache的1.2版本之前,服务器将不能启动)。如果虚拟主机是基于域名的, 它将完全不能使用,但如果它是基于IP的,那么它将很有可能工作。 然而,如果Apache不得不为一个已经包含了服务器域名的服务器产生一个完整的URL, 那么它将可能产生一个无效的URL。

以下是一个可以避免上述两个问题的配置片断.

<VirtualHost 10.0.0.1>

ServerName www.abc.dom

ServerAdmin

拒绝服务

拒绝服务主要由(至少)两种形式导致。 如果您在运行Apache 1.2以前的版本,在上述两种情况下,如果您的任何一个虚拟主机的DNS解析失败, 您都会无法启动服务。在一些情况下,DNS解析甚至不在您的控制范围之内。 比如说,如果abc.dom是您的一个客户,而且他们自己控制着DNS。 那么仅仅是因为他们删除了www.abc.dom这个记录, 都会导致您的服务器(1.2之前的版本)无法启动。

另外一种形式就更隐蔽了。比如说下面这个配置片断:

<VirtualHost www.abc.dom>

ServerAdmin

<VirtualHost www.def.dom>

ServerAdmin

假设您已经为www.abc.dom设定了10.0.0.1, 而为www.def.dom设定了10.0.0.2。 更进一步,假设def.com自己控制DNS。在这种配置下, 您已经把def.com放到了一个可以将所有指向abc.com 的所有流量据为己有的情况之下。为了达到这样的目的, 他们只需要把www.def.dom的地址解析设置成10.0.0.1就可以了。 因为他们控制着自己的DNS服务, 所以您无法阻止他们把www.def.com这个记录指向任何一个IP地址

然后,所有向10.0.0.1发出的请求 (包括用户所有类似http://www.abc.dom/任何字符的URL) 都将会为def.com这个虚拟主机所接收。 为了更好的理解着一切是怎样发生的, 您需要一个关于Apache是怎样将进入的请求分配给它的虚拟主机的深入说明。 您可以在这里发现一个完整的文档。

phpma.com

“main server”地址

在Apache 1.1中,基于域名的虚拟主机支持 需要Apache知道运行着httpd的主机的IP地址。 一般来说可以用全局变量ServerName(如果存在) 或者调用C的方法gethostname(与在命令行模式下键入hostname得到的返回值一样)。 接着它就会利用DNS来查找这个地址。目前还没有办法避免这样的查找。

如果您担心这样的查找会因为您的DNS服务器没有启动而遭到失败的结果, 您就可以在/etc/hosts中插入一条记录来确定主机名 (此文件中应该已经存在这条记录了,否则您的机器无法正常启动)。 然后,您要确认您的机器已经配置为当DNS解析失败的情况下, 它将会使用/etc/hosts根据所使用的操作系统不同, 您可能需要在/etc/resolv.conf或/etc/nsswitch.conf 两个文件中选择一个进行编辑。

如果您的服务器不必因为其他理由而使用DNS, 您也许不必在把HOSTRESORDER环境变量设置为”local”的情况下运行Apache。 这都取决于您所使用的操作系统和解析库。 如果您没有使用mod_env来控制环境变量,它还将影响到CGI。 强烈建议您参考一下您所使用的操作系统附带的man帮助或FAQ。

避免这些问题的小技巧

在VirtualHost中使用IP地址

在Listen中使用IP地址

确保所有的虚拟主机拥有显式的ServerName定义。

创建一个不包含任何服务页面的<VirtualHost_default_:*>服务器

附录:进一步的提示

涉及到DNS的情况都很让人不舒服。 在Apache 1.2 中,我们努力想让服务器在DNS解析失败的情况下至少保持能够启动, 但可能我们还是没能做到最好。在当今重编号成了必须的Internet上面, 在配置文件中显式的写明IP地址已经成为不合时宜的行为了。

上述盗窃攻击的解决办法是, 在一个正向的DNS查询结果后部署一个逆向DNS解析并将两个域名进行比较。 如果不同,就禁用相应的虚拟主机。 这个方法需要一个正确配置了的逆向域名解析服务器 (因为FTP服务器和TCP封装进行的“双重逆向”DNS处理的普遍应用,这已为大部分管理员所熟知了)。

在某些情况下,如果没有使用IP地址而DNS解析又失败了, 那么正常启动一个基于域名的虚拟主机看来是不可能的。 一些诸如禁用部分配置文件这样的权宜之计会带来比根本不能启动更遭的不可预测的结果。

随着HTTP/1.1的部署以及浏览器和代理服务器开始支持Host头, 我们完全避免使用基于IP的虚拟主机也逐渐成为可能。 这种状况下,web服务器也不必在配置时进行DNS的查询。 但在1997年3月,这些特性的采用还没有广泛到可以在重要的web服务器应用的地步。

http://www.uplinux.com/download/doc/apache/ApacheManual/dns-caveats.html#example

http://www.uplinux.com/download/doc/apache/ApacheManual/mod/core.html#virtualhost

<VirtualHost>和</VirtualHost>用于封装一组仅施用于特定虚拟主机的指令。任何在虚拟主机配置中可以使用的指令也同样可以在这里使用。当服务器接受了一个特定虚拟主机的文档请求时,它会使用封装在<VirtualHost>配置段中的指令。地址可以是

虚拟主机的IP地址;

虚拟主机IP地址对应的完整域名;

字符*,仅与NameVirtualHost *配合使用以匹配所有 的IP地址;或是

字符串_default_,与基于IP的虚拟主机联用以捕获所 有没有匹配的IP地址。

示例

<VirtualHost 10.1.2.3>

ServerAdmin

 

IPv6的地址必须放入方括号中指定,否则作为可选项的端口号将无法确定。一个IPv6的示例如下:

 

<VirtualHost [fe80::a00:20ff:fea7:ccea]>

ServerAdmin

每个虚拟主机必须对应不同的IP地址、端口号或是不同的主机名。在第一种情况下,服务器所在物理机器必须配置为可以为多个地址接受IP包。(在机器没有多个网络硬件界面的情况下,如果您的操作系统支持,您可以使用ifconfig alias命令来达到这个目的。)。

当使用基于IP的虚拟主机时,特殊的名称_default_可以在没有匹配上其它列出的虚拟主机的情况下作为匹配任何IP地址的虚拟主机。在没有进行_default_虚拟主机的设定时,在没有IP与请求匹配的情况下,将使用“主服务器”(包括所有在虚拟主机配置段之外的配置)的配置。(但请注意:任何匹配NameVirtualHost指令的IP地址既不会使用”main”服务器配置,也不会使用_default_虚拟主机的配置。 参阅基于域名的虚拟主机文档获得更多详情。)

您可以指定一个:端口来改变匹配的端口。如果没有指定,它将沿用主服务器中离它最近的那个Listen语句指定的值。您也可以指定:*来匹配那个地址上的所有端口。(当您使用_default_时,这是推荐采用的方法。)

安全提示:参阅安全提示文档获得为什么当您存储日志文件的目录对于启动服务器以外的用户来说是可写的会危及服务器安全的详细资料。

注意:<VirtualHost>的使用不会影响到Apache侦听的地址。您也许需要使用Listen来确保Apache侦听着正确的地址。

为调试程序,本机安装iis与apache,无法同时使用80端口,现给出解决方法:

方法一:

IIS5,多IP下共存,IIS为192.168.0.1,apache为192.168.0.2 原文地址

c:/Inetpub/Adminscripts

cscript adsutil.vbs set w3svc/disablesocketpooling true

该命令反馈如下disablesocketpooling : (BOOLEAN) True

重启IIS

Inetpub/AdminScripts>cscript adsutil.vbs set w3svc/disablesocketpooling true

由于 DisableSocketPooling 在 IIS 6.0 元数据库架构 (MBSchema.xml) 中被定义为有效属性,所以,您仍然可以使用 Adsutil.vbs 设置该属性,但这种设置不起作用。IIS 6.0 中的功能是新增的核心级别驱动程序 HTTP.sys 的一部分。要配置 HTTP.sys,您必须使用 Httpcfg.exe

方法二:

IIS6,多IP下共存,IIS为192.168.0.1,apache为192.168.0.2 原文地址

到2003的CD下的 support/tools/Support.cab。解压出httpcfg.exe文件,COPY到windows/system32/目录下,用法自己看帮助

命令行

绑定到某IP: httpcfg set iplisten -i 192.168.0.1

即命令使用IIS的只监听指定的IP及端口

查看绑定: httpcfg query iplisten

删除绑定: httpcfg delete iplisten -i 192.168.0.1

命令行

net stop Apache2

net stop iisadmin /y

net START Apache2

net START w3svc

保证iis下的ip设置为全局默认,Apache中httpconf设置listen 192.168.0.2:80,就应该可以两个服务同时运行,相互不冲突了。

IIS的访问地址为http://192.168.0.1,Apache访问地址为http://192.168.0.2

方法三:

网上常用的单IP共用80端口方法,不过不推荐,只是使用Apache的代理,速度有影响将apache设为使用80端口,IIS使用其它端口,比如81,然后将apache作为IIS的代理。

在httpd.conf里面,取消下面四行的注释:

LoadModule proxy_module modules/mod_proxy.so

LoadModule proxy_connect_module modules/mod_proxy_connect.so

LoadModule proxy_http_module modules/mod_proxy_http.so

LoadModule proxy_ftp_module modules/mod_proxy_ftp.so

然后建立一个虚拟主机,将该域名的所有访问转向81端口。

ServerName iloves.vicp.net

ProxyPass / http://localhost:81/

ProxyPassReverse / http://localhost:81/

这样,对外就可以只需要一个端口,即可同时使用apache和IIS的功能了

类推,使用第二种方法,你可以在IIS上配置PHP4,Apache2中配置PHP5,只需要IIS中安装PHP4,把php.ini复制到/windows目录即可,这个就不用说了吧,Apache2中,只要把PHP5的php.ini放在PHP5安装目录里面就行了

配置Apache以支持PHP5:

LoadModule php5_module “D:/PHPServer/PHP5/php5apache2.dll”

AddType application/x-httpd-php .php

DirectoryIndex index.html index.php

PHPIniDir “D:/PHPServer/PHP5”

其中最重要的一条就是 PHPIniDir,用来指明php.ini文件所在位置,即PHP5的安装目录,注意所有目录的应该改为D:/PHPServer/PHP5这种格式,而非D:/PHPServer/PHP5,IIS的访问地址为http://192.168.0.1,Apache访问地址为http://192.168.0.2

通过admin

自己动手写PHP MVC框架

来自:yuansir-web.com / yuansir@live.cn

代码下载: https://github.com/yuansir/tiny-php-framework

PHP的框架众多,对于哪个框架最好,哪个框架最烂,是否应该用框架,对于这些争论在论坛里面都有人争论,这里不做评价,
个人觉得根据自己需求,选中最佳最适合自己MVC框架,并在开发中能够体现出敏捷开发的效果就OK了,作为一个PHPer要提高自己的对PHP和MVC的框架的认识,所以自己写一个MVC框架是很有必要的,
即使不是很完善,但是自己动手写一个轻量简洁的PHP MVC框架起码对MVC的思想有一定的了解,而且经过自己后期的完善会渐渐形成一个自己熟悉的一个PHP框架。

来写一个PHP MVC框架开发的简明教程,首先声明,教程里面的框架不是一个完善的框架,只是一种思路,当然每个人对MVC框架实现的方法肯定是有差异的,希望高手多提意见多指正,和我一样的菜鸟多讨论多交流,刚接触MVC的PHPer多学习。

首先,我们在项目中建立如下目录和文件:

app
|-controller    存放控制器文件
|-model        存放模型文件
|-view        存放视图文件
|-lib        存放自定义类库
|-config    存放配置文件
|–config.php   系统配置文件
|-system    系统核心目录
|-index.php    入口文件

新件的index.php为入口文件,我们这里采用单一入口,入口文件的内容很简单:

<?php
/**
* 应用入口文件
* @copyright   Copyright(c) 2011
* @author      yuansir <yuansir@live.cn/yuansir-web.com>
* @version     1.0
*/
require dirname(__FILE__).’/system/app.php’;
require dirname(__FILE__).’/config/config.php’;
Application::run($CONFIG);

入口文件主要做了2件事,第一引入系统的驱动类,第二是引入配置文件,然后运行run()方法,传入配置作为参数,具体这2个文件是什么内容,我们接下来继续看。

先看一下config/config.php文件,里面其实是一个$CONFIG变量,这个变量存放的全局的配置:

<?php
/**
* 系统配置文件
* @copyright   Copyright(c) 2011
* @author      yuansir <yuansir@live.cn/yuansir-web.com>
* @version     1.0
*/

/*数据库配置*/
$CONFIG[‘system’][‘db’] = array(
‘db_host’           =>      ‘localhost’,
‘db_user’           =>      ‘root’,
‘db_password’       =>      ”,
‘db_database’       =>      ‘app’,
‘db_table_prefix’   =>      ‘app_’,
‘db_charset’        =>      ‘urf8’,
‘db_conn’           =>      ”,             //数据库连接标识; pconn 为长久链接,默认为即时链接

);

/*自定义类库配置*/
$CONFIG[‘system’][‘lib’] = array(
‘prefix’            =>      ‘my’   //自定义类库的文件前缀
);

$CONFIG[‘system’][‘route’] = array(
‘default_controller’             =>      ‘home’,  //系统默认控制器
‘default_action’                 =>      ‘index’,  //系统默认控制器
‘url_type’                       =>      1          /*定义URL的形式 1 为普通模式    index.php?c=controller&a=action&id=2
*              2 为PATHINFO   index.php/controller/action/id/2(暂时不实现)
*/
);

/*缓存配置*/
$CONFIG[‘system’][‘cache’] = array(
‘cache_dir’                 =>      ‘cache’, //缓存路径,相对于根目录
‘cache_prefix’              =>      ‘cache_’,//缓存文件名前缀
‘cache_time’                =>      1800,    //缓存时间默认1800秒
‘cache_mode’                =>      2,       //mode 1 为serialize ,model 2为保存为可执行文件
);

我这里有意识的定义$CONFIG[‘system’]数组表示是系统的配置文件,当然你可以在里面定义$CONFIG[‘myconfig’]为表示在定义的配置,以后在程序的控制器,模型,视图中来调用,都个很自由。
具体配置值代表什么意思注视很清楚了,下面的如果程序中有详细注释的我就不解释啦,呵呵

再来看一下system/app.php文件,主要是干嘛的:

<?php
/**
* 应用驱动类
* @copyright   Copyright(c) 2011
* @author      yuansir <yuansir@live.cn/yuansir-web.com>
* @version     1.0
*/
define(‘SYSTEM_PATH’, dirname(__FILE__));
define(‘ROOT_PATH’,  substr(SYSTEM_PATH, 0,-7));
define(‘SYS_LIB_PATH’, SYSTEM_PATH.’/lib’);
define(‘APP_LIB_PATH’, ROOT_PATH.’/lib’);
define(‘SYS_CORE_PATH’, SYSTEM_PATH.’/core’);
define(‘CONTROLLER_PATH’, ROOT_PATH.’/controller’);
define(‘MODEL_PATH’, ROOT_PATH.’/model’);
define(‘VIEW_PATH’, ROOT_PATH.’/view’);
define(‘LOG_PATH’, ROOT_PATH.’/error/’);
final class Application {
public static $_lib = null;
public static $_config = null;
public static function init() {
self::setAutoLibs();
require SYS_CORE_PATH.’/model.php’;
require SYS_CORE_PATH.’/controller.php’;

}
/**
* 创建应用
* @access      public
* @param       array   $config
*/
public static function run($config){
self::$_config = $config[‘system’];
self::init();
self::autoload();
self::$_lib[‘route’]->setUrlType(self::$_config[‘route’][‘url_type’]);
$url_array = self::$_lib[‘route’]->getUrlArray();
self::routeToCm($url_array);
}
/**
* 自动加载类库
* @access      public
* @param       array   $_lib
*/
public static function autoload(){
foreach (self::$_lib as $key => $value){
require (self::$_lib[$key]);
$lib = ucfirst($key);
self::$_lib[$key] = new $lib;
}
//初始化cache
if(is_object(self::$_lib[‘cache’])){
self::$_lib[‘cache’]->init(
ROOT_PATH.’/’.self::$_config[‘cache’][‘cache_dir’],
self::$_config[‘cache’][‘cache_prefix’],
self::$_config[‘cache’][‘cache_time’],
self::$_config[‘cache’][‘cache_mode’]
);
}
}
/**
* 加载类库
* @access      public
* @param       string  $class_name 类库名称
* @return      object
*/
public static function newLib($class_name){
$app_lib = $sys_lib = ”;
$app_lib = APP_LIB_PATH.’/’.self::$_config[‘lib’][‘prefix’].’_’.$class_name.’.php’;
$sys_lib = SYS_LIB_PATH.’/lib_’.$class_name.’.php’;

if(file_exists($app_lib)){
require ($app_lib);
$class_name = ucfirst(self::$_config[‘lib’][‘prefix’]).ucfirst($class_name);
return new $class_name;
}else if(file_exists($sys_lib)){
require ($sys_lib);
return self::$_lib[‘$class_name’] = new $class_name;
}else{
trigger_error(‘加载 ‘.$class_name.’ 类库不存在’);
}
}
/**
* 自动加载的类库
* @access      public
*/
public static function setAutoLibs(){
self::$_lib = array(
‘route’              =>      SYS_LIB_PATH.’/lib_route.php’,
‘mysql’              =>      SYS_LIB_PATH.’/lib_mysql.php’,
‘template’           =>      SYS_LIB_PATH.’/lib_template.php’,
‘cache’           =>      SYS_LIB_PATH.’/lib_cache.php’,
‘thumbnail’           =>      SYS_LIB_PATH.’/lib_thumbnail.php’
);
}
/**
* 根据URL分发到Controller和Model
* @access      public
* @param       array   $url_array
*/
public static function routeToCm($url_array = array()){
$app = ”;
$controller = ”;
$action = ”;
$model = ”;
$params = ”;

if(isset($url_array[‘app’])){
$app = $url_array[‘app’];
}

if(isset($url_array[‘controller’])){
$controller = $model = $url_array[‘controller’];
if($app){
$controller_file = CONTROLLER_PATH.’/’.$app.’/’.$controller.’Controller.php’;
$model_file = MODEL_PATH.’/’.$app.’/’.$model.’Model.php’;
}else{
$controller_file = CONTROLLER_PATH.’/’.$controller.’Controller.php’;
$model_file = MODEL_PATH.’/’.$model.’Model.php’;
}
}else{
$controller = $model = self::$_config[‘route’][‘default_controller’];
if($app){
$controller_file = CONTROLLER_PATH.’/’.$app.’/’.self::$_config[‘route’][‘default_controller’].’Controller.php’;
$model_file = MODEL_PATH.’/’.$app.’/’.self::$_config[‘route’][‘default_controller’].’Model.php’;
}else{
$controller_file = CONTROLLER_PATH.’/’.self::$_config[‘route’][‘default_controller’].’Controller.php’;
$model_file = MODEL_PATH.’/’.self::$_config[‘route’][‘default_controller’].’Model.php’;
}
}
if(isset($url_array[‘action’])){
$action = $url_array[‘action’];
}else{
$action = self::$_config[‘route’][‘default_action’];
}

if(isset($url_array[‘params’])){
$params = $url_array[‘params’];
}
if(file_exists($controller_file)){
if (file_exists($model_file)) {
require $model_file;
}
require $controller_file;
$controller = $controller.’Controller’;
$controller = new $controller;
if($action){
if(method_exists($controller, $action)){
isset($params) ? $controller ->$action($params) : $controller ->$action();
}else{
die(‘控制器方法不存在’);
}
}else{
die(‘控制器方法不存在’);
}
}else{
die(‘控制器不存在’);
}
}

}

我叫它框架驱动类,也许不合适,但是我是这样理解的,它用来启动这个框架,做好一些初始化的工作,下面我来详细分析一下每个方法的功能:
1.首先时定义了一些常量,很明了,不解释了
2.setAutoLibs 这个方法其实就是设定那些是系统启动时自动加载的类库,类库文件都存放在SYS_LIB_PATH下面,以lib_开头的,当然这里你可以根据自己的规则来命名
3.autoload 这个方法就是用来引入你要自动加载的类,然后来实例化,用$_lib数组来保存类的实例,比如$lib[‘route’]是system/lib/lib_route.php中lib_route类的实例
4.newLib 这个方法是用来加载你自定义的类的,自定义类存放在根目录下的lib中,但是自定义的类的文件前缀是你自己定义的,看系统配置文件里面有,我定义的是my,这样我就可以在lib
目录下新建一个自定义的类了,比如 my_test.php
<?php
class MyTest {
function __construct() {
echo “my lib test”;
}
}
为什么类名这样命名,看下newLib方法的实现就知道,其实这些你完全可以定义自己的规则,这个方法会首先去着lib下面有没有这个类,如果有就会引入实例化,如果没有就去找系统目录下面的类,有就实例化
5.init 就是一个初始化的方法,里面其实就是加载自动加载的类,以及引入核心控制器和核心模型,这个2个核心文件过会我们再来分析
6.run 方法就是启动这个框架的了,里面的最后2步很重要,就是获取URL然后拆分成一个数组的形似,然后由routeToCm来分发到Controller和Model
7.routeToCm 很重要,根据URL分发到Controller和Model,这个我们过会来说

在run方法中
self::$_lib[‘route’]->setUrlType(self::$_config[‘route’][‘url_type’]); //设置url的类型
$url_array = self::$_lib[‘route’]->getUrlArray();                      //将url转发成数组
好吧,我们来看下route的系统类到底做了说明

<?php
/**
* URL处理类
* @copyright   Copyright(c) 2011
* @author      yuansir <yuansir@live.cn/yuansir-web.com>
* @version     1.0
*/
final class Route{
public $url_query;
public $url_type;
public $route_url = array();

public function __construct() {
$this->url_query = parse_url($_SERVER[‘REQUEST_URI’]);
}
/**
* 设置URL类型
* @access      public
*/
public function setUrlType($url_type = 2){
if($url_type > 0 && $url_type <3){
$this->url_type = $url_type;
}else{
trigger_error(“指定的URL模式不存在!”);
}
}

/**
* 获取数组形式的URL
* @access      public
*/
public function getUrlArray(){
$this->makeUrl();
return $this->route_url;
}
/**
* @access      public
*/
public function makeUrl(){
switch ($this->url_type){
case 1:
$this->querytToArray();
break;
case 2:
$this->pathinfoToArray();
break;
}
}
/**
* 将query形式的URL转化成数组
* @access      public
*/
public function querytToArray(){
$arr = !empty ($this->url_query[‘query’]) ?explode(‘&’, $this->url_query[‘query’]) :array();
$array = $tmp = array();
if (count($arr) > 0) {
foreach ($arr as $item) {
$tmp = explode(‘=’, $item);
$array[$tmp[0]] = $tmp[1];
}
if (isset($array[‘app’])) {
$this->route_url[‘app’] = $array[‘app’];
unset($array[‘app’]);
}
if (isset($array[‘controller’])) {
$this->route_url[‘controller’] = $array[‘controller’];
unset($array[‘controller’]);
}
if (isset($array[‘action’])) {
$this->route_url[‘action’] = $array[‘action’];
unset($array[‘action’]);
}
if(count($array) > 0){
$this->route_url[‘params’] = $array;
}
}else{
$this->route_url = array();
}
}
/**
* 将PATH_INFO的URL形式转化为数组
* @access      public
*/
public function pathinfoToArray(){

}
}

注意querytToArray方法,将将query形式的URL转化成数组,比如原来是localhost/myapp/index.php/app=admin&controller=index&action=edit&id=9&fid=10 这样的url就会被转发成如下的数组
array(
‘app’        =>’admin’,
‘controller’    =>’index’,
‘action’    =>’edit’,
‘id’        =>array(
‘id’    =>9,
‘fid’    =>10
)
)
这下再耐心来看下我写的笨拙的routeToCm,来通过数组参数来分发到控制器,找到控制器以后还要引用相应的模型,然后就实例化控制器和模型,呵呵,貌似有点成型了。

下面就要开始实现 控制器-模型-视图了
我们的思路是这样的,建立一个核心模型和核心控制器,在以后自己的模型和控制器中来继承核心模型和控制器,核心模型和控制器中主要可以是一些通用的方法和必须的组建的加载,下面我们先来写核心控制器,
新建system/core/controller.php
<?php
/**
* 核心控制器
* @copyright   Copyright(c) 2011
* @author      yuansir <yuansir@live.cn/yuansir-web.com>
* @version     1.0
*/
class Controller{

public function __construct() {
// header(‘Content-type:text/html;chartset=utf-8’);
}
/**
* 实例化模型
* @access      final   protected
* @param       string  $model  模型名称
*/
final protected function model($model) {
if (empty($model)) {
trigger_error(‘不能实例化空模型’);
}
$model_name = $model . ‘Model’;
return new $model_name;
}
/**
* 加载类库
* @param string $lib   类库名称
* @param Bool  $my     如果FALSE默认加载系统自动加载的类库,如果为TRUE则加载非自动加载类库
@return object
*/
final protected function load($lib,$auto = TRUE){
if(empty($lib)){
trigger_error(‘加载类库名不能为空’);
}elseif($auto === TRUE){
return Application::$_lib[$lib];
}elseif($auto === FALSE){
return  Application::newLib($lib);
}
}
/**
* 加载系统配置,默认为系统配置 $CONFIG[‘system’][$config]
* @access      final   protected
* @param       string  $config 配置名
*/
final   protected function config($config){
return Application::$_config[$config];
}
/**
* 加载模板文件
* @access      final   protect
* @param       string  $path   模板路径
* @return      string  模板字符串
*/
final protected function showTemplate($path,$data = array()){
$template =  $this->load(‘template’);
$template->init($path,$data);
$template->outPut();
}
}

注释都写的很清楚了吧,其实很简单,这里的加载模板的方法中load了一个系统自动加载的模板类,这个类我们在建立视图的时候再来讲,然后我们再来建核心模型的文件
system/core/model.php

<?php
/**
* 核心模型类
* @copyright   Copyright(c) 2011
* @author      yuansir <yuansir@live.cn/yuansir-web.com>
* @version     1.0
*/
class Model {
protected $db = null;

final public function __construct() {
header(‘Content-type:text/html;chartset=utf-8’);
$this->db = $this->load(‘mysql’);
$config_db = $this->config(‘db’);
$this->db->init(
$config_db[‘db_host’],
$config_db[‘db_user’],
$config_db[‘db_password’],
$config_db[‘db_database’],
$config_db[‘db_conn’],
$config_db[‘db_charset’]
);                                            //初始话数据库类
}
/**
* 根据表前缀获取表名
* @access      final   protected
* @param       string  $table_name    表名
*/
final protected function table($table_name){
$config_db = $this->config(‘db’);
return $config_db[‘db_table_prefix’].$table_name;
}
/**
* 加载类库
* @param string $lib   类库名称
* @param Bool  $my     如果FALSE默认加载系统自动加载的类库,如果为TRUE则加载自定义类库
@return type
*/
final protected function load($lib,$my = FALSE){
if(empty($lib)){
trigger_error(‘加载类库名不能为空’);
}elseif($my === FALSE){
return Application::$_lib[$lib];
}elseif($my === TRUE){
return  Application::newLib($lib);
}
}
/**
* 加载系统配置,默认为系统配置 $CONFIG[‘system’][$config]
* @access      final   protected
* @param       string  $config 配置名
*/
final   protected function config($config=”){
return Application::$_config[$config];
}
}

因为模型基本是处理数据库的相关内容,所以我们加载了mysql类,这个mysql类就不在这里写了,你可以自己根据习惯写自己的mysql的操作类,如果你想支持其他的数据库,完全可以自己灵活添加。

核心模型控制器已经有了,其实里面还可以添加其他你觉得必要的全局函数,这样我们开始新建一个自己的控制器和模型,来实例运用一下
新建controller/testController.php

<?php
/**
* 测试控制器
* @copyright   Copyright(c) 2011
* @author      yuansir <yuansir@live.cn/yuansir-web.com>
* @version     1.0
*/
class testController extends Controller {

public function __construct() {
parent::__construct();
}

public function index() {
echo “test”;
}

public function testDb() {
$modTest = $this->model(‘test’);        //示例化test模型
$databases = $modTest->testDatebases(); //调用test模型中 testDatebases()方法
var_dump($databases);
}
}

testController 继承我们的核心控制器,其实在以后的每个控制器中都要继承的,现在我们通过浏览器访问 http://localhost/myapp/index.php?controller=test ,哈哈,可以输出 test 字符串了
然后我们再新建一个模型model/testModel.php

<?php
/**
* 测试模型
* @copyright   Copyright(c) 2011
* @author      yuansir <yuansir@live.cn/yuansir-web.com>
* @version     1.0
*/
class testModel extends Model{

function testDatabases(){
$this->db->show_databases();
}
}

其实就是定义了一个获取所有的数据库的方法,打开浏览器访问 http://localhost/myapp/index.php?controller=test&action=testDb,不管你信不信,反正我的浏览器是输出了所有的数据库了

现在就差视图了,其实在核心控制器的controller.php文件中已经有了一个showTemplate方法,其实就是实现了加载模板类,$data就是我们要传递给模板的变量,然后输出模板
/**
* 加载模板文件
* @access      final   protect
* @param       string  $path   模板路径
* @param       array   $data   模板变量
* @return      string  模板字符串
*/
final protected function showTemplate($path,$data = array()){
$template =  $this->load(‘template’);
$template->init($path,$data);
$template->outPut();
}

下面我们来看一下template类

<?php
/**
* 模板类
* @copyright   Copyright(c) 2011
* @author      yuansir <yuansir@live.cn/yuansir-web.com>
* @version     1.0
*/
final class Template {
public $template_name = null;
public $data = array();
public $out_put = null;

public function init($template_name,$data = array()) {
$this->template_name = $template_name;
$this->data = $data;
$this->fetch();
}
/**
* 加载模板文件
* @access      public
* @param       string  $file
*/
public function fetch() {
$view_file = VIEW_PATH . ‘/’ . $this->template_name . ‘.php’;
if (file_exists($view_file)) {
extract($this->data);
ob_start();
include $view_file;
$content = ob_get_contents();
ob_end_clean();
$this->out_put =  $content;
} else {
trigger_error(‘加载 ‘ . $view_file . ‘ 模板不存在’);
}
}
/**
* 输出模板
* @access      public
* @return      string
*/
public function outPut(){
echo $this->out_put;
}
是不是简单,就是引入你的静态模版文件,放在缓冲区,然后输出,其实如果你想静态化某个模版,那个这个放在缓冲区的$this->out_put就有用了,你可以在里面添加一个静态化的方法。
好了,现在我们来在新建一个视图文件 view/test.php
<html>
<body>
这是<?php echo $test; ?>,呵呵
</body>
<html>
然后修改一些我们的testController.php中的index()
public function index() {
$data[‘test’] = “yuansir-web.com”;
$this->showTemplate(‘test’, $data);
}
再来浏览 http://localhost/myapp/index.php?controller=test ,可以输出 “这是 yuansir-web.com,呵呵”,那么显然我们的视图也完成了。

这样我们的自己写PHP的MVC的框架就完成了,再补充一下,有人可能疑惑如果我是想建立前台后台的,单一入口怎么办呢,其实你要是从头就看我的这个教程,看下代码就会发现,其实只要在 controller目录下新建
一个admin目录就可以在里面写控制器了,比如controller/admin/testController.php 模板引用也是同样的道理,建立 view/admin/test.php ,然后模板加上路径就可以了,$this->showTemplate(‘admin/test’, $data);
是不是很简单,很灵活。

好了,这样我们《自己动手写PHP MVC框架》的教程就结束了,你可以模仿自己写一个,也可以根据自己的思路来写一个,我教程中的可以自己扩增成一个完善的框架,再次申明一下,教程中的代码不完善,没有做过任何基准测试,效率神马的不考虑,便捷性神马的看个人,呵呵

通过admin

【转载分享】八个移动产品设计必备网站

【本文系外部转贴,原文地址:http://www.web20share.com/2012/05/mobile-app-design-sites.html
大家接触和涉及到的移动产品的设计项目越来越多,相关的移动应用素材库和优秀网站变得十分重要。在这里转载八个移动产品设计必备网站。
—————————————————————————————————————————————————–
好吧,又在爱库上发现了很棒的专辑,和大家分享!移动产品设计人员一定需要大量的使用其他各类应用,并且需要在产品设计时大量参考其他的移动应用的产品设计,这时如果有一些网站可以将很多优秀应用的不同流程分类展示,那一定是移动产品设计人员必备的网站!

一、Patterns of Design


Patterns是一个分享ios应用UI界面的网站,专注于分享iOS应用UI界面的细节,按照设计元素进行分类,按照iOS常用功能对各类UI进行分类展示。(Via

链接:http://www.patternsofdesign.co.uk/

二、 iOS UI Patterns


Splashscreens / iOS UI Patterns (beta) ,整理/罗列了许多精彩的iOS 应用界面截图,并且按照分类将这些截图分类,比如Activity,Login,About,Calendar,Seeting,Share等各种类型的不同应用的实现效果。(Via

链接:http://pttrns.com/

 三、Appsites

优秀移动应用网站设计展示,非常的赞!

链接:http://www.appsites.com/

四、Dribbble

Dribbble应该大家都比较熟悉,是一个设计师交流和分享自己设计作品的社区。上面有很多非常棒的移动产品设计作品。

链接:http://dribbble.com/

五、Tappgala


分享最棒的手机产品界面设计,做手机产品的朋友们不可错过这个站。

链接:http://www.tappgala.com/

六、Mobile Design Pattern Gallery


移动设计书籍、移动原型分享的网站。

链接:http://www.mobiledesignpatterngallery.com/

七、Code4App


Code4App是一个移动平台的代码库。我们目前只推出ios平台,会慢慢加入其他移动平台,如Android,WP。Code4App收集了iOS平台几百个代码,并且配有效果图和演示视频。

链接:http://code4app.com/

八、iOS Inspries Me


主要是展示优秀的iOS平台上应用的设计,icon及相关资源。Showcase of the best looking iPhone & iPad app icons, app interfaces, app websites & resources

链接:http://www.iosinspires.me/

更多可以查看这里:http://ikeepu.com/list/63970

通过admin

php实现长连接的方法和注意事项

php可以通过set_time_limit(0);来取消php脚步超时限制,从而达到长连接的效果。例子代码如下:

 

程序代码

<?php

echo “每隔3秒输出一次<br />”;

set_time_limit(0); //保证php程序运行不超时退出

while(1) {

echo date(“H:i:s”).”<br />”;

ob_flush();

flush(); //刷新并输出PHP缓冲数据

sleep(3); //延迟3秒

}

?>

 

示例代码2:

 

程序代码

set_time_limit(0);

header(“Connection:Keep-Alive”);

header(“Proxy-Connection:Keep-Alive”);

for($i=0;$i<60;$i++) {

print ‘text’.$i.'<br>’;

ob_flush();

flush();

sleep(1);

clearstatcache();

}

 

这里调用了ob_flush();   flush();来强制输出数据到缓冲区,这样就能在脚步返回之前及时返回数据到浏览器。另外不冲下flush和ob_flush的使用上有一些特别容易犯错的地方,造成无法刷新输出缓冲。

一. flush和ob_flush的正确顺序,正确应是,先ob_flush再flush,如下:

ob_flush();

flush();

如果Web服务器的操作系统是windows系统,那顺序颠倒或者不使用ob_flush()也不会出现问题。但是在Linux系统上就无法刷新输出缓冲。

 

二. 使用ob_flush()前,确保前面的内容大小足够4069字符。

一些Web服务器的output_buffering默认是4069字符或者更大,即输出内容必须达到4069字符服务器才会flush刷新输出缓冲,为了确保flush有效,最好在ob_flush()函数前有以下语句:

print str_repeat(” “, 4096);

以确保到达output_buffering值。

 

for ($i=10; $i>0; $i–)

{

echo $i.'<br />’;

ob_flush();

flush();

sleep(1);

}

ob_end_flush();