如何编写可重用的MySQL查询

没有评论

2011 年 01 月 15 日 at 上午 11:18分类:MySQL | WEB开发

当人们提及可重用的查询的时候,立即映入脑海的往往就是存储过程了。虽然这些存储过程是编写可重用代码不可分割的一部分,但要记住的是,它们只是很少的一部分而已,而非全部。此外,其它可重用代码包括视图、内置函数以及用户定义的函数。在本文中,我们将向读者详细介绍如何组合这些元素,以令我们的选择语句可以更好的适用于各种查询。

  一、关于视图
  视图的用途很多,例如简化复杂的模式及查询,或者提供安全性等等。视图提供安全性的一种途径是对开发者隐藏审计字段。视图还可通过减少列的数目来提高性能。这个想法是只引用索引字段,而索引字段的搜索速度是非常之快的。实际上,这种想法实现起来很费劲,因为你必须确保不会访问隐藏列。然而,我们这里主要是利用视图模拟两个或更多个表之间的连接,以降低查询的复杂性。很多时候,要想将数据库中用户的概要信息整理成符合第三范式的形式,可能需要多达六次连接操作,例如:

select * 
from   Users u
  inner join UserPhoneNumbers upn on u.user_id          = upn.user_id
  inner join UserScreenNames  usn on u.user_id          = usn.user_id
  inner join UserAffiliations ua  on u.user_id          = ua.user_id
  inner join Affiliations     a   on a.affiliation_id   = ua.affiliation_id
  inner join UserWorkHistory  uwh on u.user_id          = uwh.user_id
  inner join Affiliations     wa  on uwh.affiliation_id = wa.affiliation_id

  下面,我们用一个视图来替换上面的查找过程:

CREATE VIEW `vusers` AS
  select * 
  from   Users u
    inner join UserPhoneNumbers upn on u.user_id          = upn.user_id
    inner join UserScreenNames  usn on u.user_id          = usn.user_id
    inner join UserAffiliations ua  on u.user_id          = ua.user_id
    inner join Affiliations     a   on a.affiliation_id   = ua.affiliation_id
    inner join UserWorkHistory  uwh on u.user_id          = uwh.user_id
    inner join Affiliations     wa  on uwh.affiliation_id = wa.affiliation_id;

  现在,我们可以通过以下简单的选择语句来检索用户概要信息了:

select * 
from   vusers u
where  u.user_id = 100

二、关于MySQL内置函数
  GROUP_CONCAT()函数可以用来聚集表中的所有行,并返回组成交叉表水平轴的SELECT列表。实际上,这使得将交叉表的选择语句移植到存储过程中成为可能。其他的函数,如Count()、Month()和MonthName(),以及过滤语句,如CASE WHEN ELSE,都可以让我们的代码更具通用性。
  三、建立自己的函数
  如果在MySQL内建的函数中没有我们所想要的,那么我们不妨自己动手,丰衣足食。 在编写自己的函数的时候,一定要考虑到该函数的通用性。
  下面是一个示例函数,用来检查是否指定了强制性的存储过程参数。这里不允许使用空行或者空白符,所以该函数将进行相应的检查:

BEGIN
  DECLARE isEmpty TINYINT;
  SET isEmpty = (param_name IS NULL or char_length(trim(param_name)) = 0);
  RETURN isEmpty;
END

  注意,在我们的函数中调用了内建的两个函数,即char_length()和trim()。现在,我们总能够将其作为一个通用函数使用了。
  需要提示的是,在我们编写自己的函数之前,最好先在网上搜索一下,看看别人是否已经做过这项工作了,免得重复相同的工作。这时,我们要特别留意那些MySQL函数仓库站点,如www.mysqludf.org,我们很可能在这里找到所需的函数。

四、存储过程
  我们知道,存储过程能够起到代码模块化和集中化的作用。然而,将SQL代码放入存储过程本身并不意味着就能提高通用性或者可重用性。举例来说,下面的语句将生成一份反映各员工去年奖金总数的报告:

SELECT e.name, 
       e.salary, 
       COUNT(b.bonus_id) AS 'Total Bonuses'
FROM employees e 
       LEFT OUTER JOIN 
(SELECT emp_id, bonus_id  FROM bonuses WHERE YEAR(award_date) = 2010) AS b
 ON e.id = b.emp_id
GROUP BY e.id;

  下面我们将其转变成一个存储过程:

CREATE PROCEDURE `p_2010_bonuses_lst`() 
LANGUAGE SQL 
NOT DETERMINISTIC 
CONTAINS SQL 
SQL SECURITY DEFINER 
BEGIN 
SELECT e.name, 
       e.salary, 
       COUNT(b.bonus_id) AS 'Total Bonuses'
FROM employees e 
LEFT OUTER JOIN 
 (SELECT emp_id, bonus_id FROM bonuses WHERE YEAR(award_date) = 2010) AS b
  ON e.id = b.emp_id
GROUP BY e.id;

END;

  现在,其他人或程序就可以方便的使用这个过程了,不过这里有个时间限制,就是只能在明年之前使用。但是,我们为什么要创建这种有限制的东西呢?因为,我们每年都可能需要生成相似的报告,所以下面我们要去掉这个时间限制。
  为此,我们将该过程中的硬编码的日期删除掉,如下所示:

CREATE PROCEDURE `p_yearly_bonuses_lst`(IN `@year` INT) 
LANGUAGE SQL 
NOT DETERMINISTIC 
CONTAINS SQL 
SQL SECURITY DEFINER 
BEGIN 
SELECT e.name, 
       e.salary, 
       COUNT(b.bonus_id) AS 'Total Bonuses'
FROM employees e 
LEFT OUTER JOIN 
 (SELECT emp_id, bonus_id FROM bonuses WHERE YEAR(award_date) = @year) AS b
  ON e.id = b.emp_id
GROUP BY e.id;

END;

  作为一名有上进心的开发人员,我们会自问是否可以做得更好呢?客户程序也许对起始日期和结束日期方面有更高的灵活性要求,比如他们可能要求日期范围与财政年度一致。从这方面考虑,不管客户程序是否要求,我们的都必须提供一个起始日期和终止日期参数。 MySQL有一个非常不错的BETWEEN运算符,可以用来处理某个范围内的值。
  下面我们就将其用于起始日期和终止日期:

CREATE PROCEDURE `p_bonuses_lst`( IN `@StartDate` DATETIME, 
                                  IN `@EndDate`   DATETIME ) 
LANGUAGE SQL 
NOT DETERMINISTIC 
CONTAINS SQL 
SQL SECURITY DEFINER 
BEGIN 
SELECT e.name, 
       e.salary, 
       COUNT(b.bonus_id) AS 'Total Bonuses'
FROM employees e 
LEFT OUTER JOIN 
 (SELECT emp_id, 
         bonus_id 
  FROM   bonuses 
  WHERE  award_date Between @StartDate AND @EndDate) AS b
  ON e.id = b.emp_id
GROUP BY e.id;

END;

  五、小结
  在本文中,我们讨论了如何利用视图、内建函数和用户定义函数以及存储过程来提高SELECT查询的通用性和可重用性。为了便于理解,我们还给出了一些实例代码,以便帮助读者理解本文讲到的内容。根据局部性原理,现在执行的操作,近期内很可能会再次执行该操作,所以提高可重用性是非常有帮助的。

header常用指令

没有评论

2011 年 01 月 15 日 at 上午 11:11分类:PHP | WEB开发

/ fix 404 pages:   用这个header指令来解决URL重写产生的404 header
header(’HTTP/1.1 200 OK’);  
 
// set 404 header:   页面没找到
header(’HTTP/1.1 404 Not Found’);  
 
//页面被永久删除,可以告诉搜索引擎更新它们的urls
// set Moved Permanently header (good for redrictions)  
// use with location header  
header(’HTTP/1.1 301 Moved Permanently’);

// 访问受限
header(’HTTP/1.1 403 Forbidden’);

// 服务器错误
header(’HTTP/1.1 500 Internal Server Error’);
 
// 重定向到一个新的位置
// redirect to a new location:  
header(’Location: http://www.example.org/’);  
 
延迟一段时间后重定向
// redrict with delay:  
header(’Refresh: 10; url=http://www.example.org/’);  
print ‘You will be redirected in 10 seconds’;  
 
// 覆盖 X-Powered-By value
// override X-Powered-By: PHP:  
header(’X-Powered-By: PHP/4.4.0′);  
header(’X-Powered-By: Brain/0.6b’);  
 
// 内容语言 (en = English)
// content language (en = English)  
header(’Content-language: en’);  
 
//最后修改时间(在缓存的时候可以用到)
// last modified (good for caching)  
$time = time() - 60; // or filemtime($fn), etc  
header(’Last-Modified: ‘.gmdate(’D, d M Y H:i:s’, $time).’ GMT’);  
 
// 告诉浏览器要获取的内容还没有更新
// header for telling the browser that the content  
// did not get changed  
header(’HTTP/1.1 304 Not Modified’);  
 
// 设置内容的长度 (缓存的时候可以用到):
// set content length (good for caching):  
header(’Content-Length: 1234′);  
 
// 用来下载文件:
// Headers for an download:  
header(’Content-Type: application/octet-stream’);  
header(’Content-Disposition: attachment; filename=”example.zip”‘);  
header(’Content-Transfer-Encoding: binary’);  
 
// 禁止缓存当前文档:
// load the file to send:readfile(’example.zip’);  
// Disable caching of the current document:  
header(’Cache-Control: no-cache, no-store, max-age=0, must-revalidate’);  
header(’Expires: Mon, 26 Jul 1997 05:00:00 GMT’);  

// 设置内容类型:
// Date in the pastheader(’Pragma: no-cache’);  
// set content type:  
header(’Content-Type: text/html; charset=iso-8859-1′);  
header(’Content-Type: text/html; charset=utf-8′);  
header(’Content-Type: text/plain’);  
 
// plain text file  
header(’Content-Type: image/jpeg’);   
 
// JPG picture  
header(’Content-Type: application/zip’);   
 
// ZIP file  
header(’Content-Type: application/pdf’);   
 
// PDF file  
header(’Content-Type: audio/mpeg’);   
 
// Audio MPEG (MP3,…) file  
header(’Content-Type: application/x-shockwave-flash’);   
 
// 显示登录对话框,可以用来进行HTTP认证
// Flash animation// show sign in box  
header(’HTTP/1.1 401 Unauthorized’);  
header(’WWW-Authenticate: Basic realm=”Top Secret”‘);  
print ‘Text that will be displayed if the user hits cancel or ‘;  
print ‘enters wrong login data’;?>

基本的header Content-Type类型

<?php

$mimetypes = array(

‘ez’ => ‘application/andrew-inset’,

‘hqx’ => ‘application/mac-binhex40′,

‘cpt’ => ‘application/mac-compactpro’,

‘doc’ => ‘application/msword’,

‘bin’ => ‘application/octet-stream’,

‘dms’ => ‘application/octet-stream’,

‘lha’ => ‘application/octet-stream’,

‘lzh’ => ‘application/octet-stream’,

‘exe’ => ‘application/octet-stream’,

‘class’ => ‘application/octet-stream’,

’so’ => ‘application/octet-stream’,

‘dll’ => ‘application/octet-stream’,

‘oda’ => ‘application/oda’,

‘pdf’ => ‘application/pdf’,

‘ai’ => ‘application/postscript’,

‘eps’ => ‘application/postscript’,

‘ps’ => ‘application/postscript’,

’smi’ => ‘application/smil’,

’smil’ => ‘application/smil’,

‘mif’ => ‘application/vnd.mif’,

‘xls’ => ‘application/vnd.ms-excel’,

‘ppt’ => ‘application/vnd.ms-powerpoint’,

‘wbxml’ => ‘application/vnd.wap.wbxml’,

‘wmlc’ => ‘application/vnd.wap.wmlc’,

‘wmlsc’ => ‘application/vnd.wap.wmlscriptc’,

‘bcpio’ => ‘application/x-bcpio’,

‘vcd’ => ‘application/x-cdlink’,

‘pgn’ => ‘application/x-chess-pgn’,

‘cpio’ => ‘application/x-cpio’,

‘csh’ => ‘application/x-csh’,

‘dcr’ => ‘application/x-director’,

‘dir’ => ‘application/x-director’,

‘dxr’ => ‘application/x-director’,

‘dvi’ => ‘application/x-dvi’,

’spl’ => ‘application/x-futuresplash’,

‘gtar’ => ‘application/x-gtar’,

‘hdf’ => ‘application/x-hdf’,

‘js’ => ‘application/x-javascript’,

’skp’ => ‘application/x-koan’,

’skd’ => ‘application/x-koan’,

’skt’ => ‘application/x-koan’,

’skm’ => ‘application/x-koan’,

‘latex’ => ‘application/x-latex’,

‘nc’ => ‘application/x-netcdf’,

‘cdf’ => ‘application/x-netcdf’,

’sh’ => ‘application/x-sh’,

’shar’ => ‘application/x-shar’,

’swf’ => ‘application/x-shockwave-flash’,

’sit’ => ‘application/x-stuffit’,

’sv4cpio’ => ‘application/x-sv4cpio’,

’sv4crc’ => ‘application/x-sv4crc’,

‘tar’ => ‘application/x-tar’,

‘tcl’ => ‘application/x-tcl’,

‘tex’ => ‘application/x-tex’,

‘texinfo’ => ‘application/x-texinfo’,

‘texi’ => ‘application/x-texinfo’,

‘t’ => ‘application/x-troff’,

‘tr’ => ‘application/x-troff’,

‘roff’ => ‘application/x-troff’,

‘man’ => ‘application/x-troff-man’,

‘me’ => ‘application/x-troff-me’,

‘ms’ => ‘application/x-troff-ms’,

‘ustar’ => ‘application/x-ustar’,

’src’ => ‘application/x-wais-source’,

‘xhtml’ => ‘application/xhtml+xml’,

‘xht’ => ‘application/xhtml+xml’,

‘zip’ => ‘application/zip’,

‘au’ => ‘audio/basic’,

’snd’ => ‘audio/basic’,

‘mid’ => ‘audio/midi’,

‘midi’ => ‘audio/midi’,

‘kar’ => ‘audio/midi’,

‘mpga’ => ‘audio/mpeg’,

‘mp2′ => ‘audio/mpeg’,

‘mp3′ => ‘audio/mpeg’,

‘aif’ => ‘audio/x-aiff’,

‘aiff’ => ‘audio/x-aiff’,

‘aifc’ => ‘audio/x-aiff’,

‘m3u’ => ‘audio/x-mpegurl’,

‘ram’ => ‘audio/x-pn-realaudio’,

‘rm’ => ‘audio/x-pn-realaudio’,

‘rpm’ => ‘audio/x-pn-realaudio-plugin’,

‘ra’ => ‘audio/x-realaudio’,

‘wav’ => ‘audio/x-wav’,

‘pdb’ => ‘chemical/x-pdb’,

‘xyz’ => ‘chemical/x-xyz’,

‘bmp’ => ‘image/bmp’,

‘gif’ => ‘image/gif’,

‘ief’ => ‘image/ief’,

‘jpeg’ => ‘image/jpeg’,

‘jpg’ => ‘image/jpeg’,

‘jpe’ => ‘image/jpeg’,

‘png’ => ‘image/png’,

‘tiff’ => ‘image/tiff’,

‘tif’ => ‘image/tiff’,

‘djvu’ => ‘image/vnd.djvu’,

‘djv’ => ‘image/vnd.djvu’,

‘wbmp’ => ‘image/vnd.wap.wbmp’,

‘ras’ => ‘image/x-cmu-raster’,

‘pnm’ => ‘image/x-portable-anymap’,

‘pbm’ => ‘image/x-portable-bitmap’,

‘pgm’ => ‘image/x-portable-graymap’,

‘ppm’ => ‘image/x-portable-pixmap’,

‘rgb’ => ‘image/x-rgb’,

‘xbm’ => ‘image/x-xbitmap’,

‘xpm’ => ‘image/x-xpixmap’,

‘xwd’ => ‘image/x-xwindowdump’,

‘igs’ => ‘model/iges’,

‘iges’ => ‘model/iges’,

‘msh’ => ‘model/mesh’,

‘mesh’ => ‘model/mesh’,

’silo’ => ‘model/mesh’,

‘wrl’ => ‘model/vrml’,

‘vrml’ => ‘model/vrml’,

‘css’ => ‘text/css’,

‘html’ => ‘text/html’,

‘htm’ => ‘text/html’,

‘asc’ => ‘text/plain’,

‘txt’ => ‘text/plain’,

‘rtx’ => ‘text/richtext’,

‘rtf’ => ‘text/rtf’,

’sgml’ => ‘text/sgml’,

’sgm’ => ‘text/sgml’,

‘tsv’ => ‘text/tab-separated-values’,

‘wml’ => ‘text/vnd.wap.wml’,

‘wmls’ => ‘text/vnd.wap.wmlscript’,

‘etx’ => ‘text/x-setext’,

‘xsl’ => ‘text/xml’,

‘xml’ => ‘text/xml’,

‘mpeg’ => ‘video/mpeg’,

‘mpg’ => ‘video/mpeg’,

‘mpe’ => ‘video/mpeg’,

‘qt’ => ‘video/quicktime’,

‘mov’ => ‘video/quicktime’,

‘mxu’ => ‘video/vnd.mpegurl’,

‘avi’ => ‘video/x-msvideo’,

‘movie’ => ‘video/x-sgi-movie’,

‘ice’ => ‘x-conference/x-cooltalk’,

);
?>

用法就是header (“Content-type: image/gif”);

ubuntu中grub配置文件menu.lst的写法

没有评论

2011 年 01 月 12 日 at 上午 9:54分类:Linux

menu.lst位于/boot/grub/menu.lst,而/boot/grub/grub.conf相当于是menu.lst在windows下的快捷方式(重装系统有时破坏GRUB后,menu.lst丢失而无法

启动GRUB菜单时就需要在/boot下建立menu.lst后再和

grub.conf建立链接来修复,建立链接是:ln -s menu.lst grub.conf

(注意两文件的前后关系)),我们来学习如何编写GRUB的配置文件menu.lst.

首先来看一下/boot/grub/menu.lst中的内容:
default=0
timeout=5
#splashimage=(hd0,6)/boot/grub/splash.xpm.gz
hiddenmenu
title Fedora Core (2.6.11-1.1369_FC4)
root (hd0,6)
kernel /boot/vmlinuz-2.6.11-1.1369_FC4 ro root=LABEL=/
initrd /boot/initrd-2.6.11-1.1369_FC4.img
title Windows XP
rootnoverify (hd0,0)
chainloader +1
其中:
a,default=0
表示默认启动的第0号的操作系统,在GRUB中,title定义了启动的操作系统,从第1个开始,GRUB中是0,而第2个是1,依次类推…
b,timeout=5
表示的是出现GRUB界面后,无操作情况下进入default设定的操作系统的时间,如果上下移动选择,则该选项无效
c,splashimage=(hd0,6)/boot/grub/splah.xpm.gz
表示的是允许出现的GRUB背景的path,显然(hd0,6)指定了分区(不知能否这么解释,呵呵),而后边的则是正常的path(在例子中,用#把它注释,为一可选项)
d,hiddenmenu
表示隐藏GRUB的启动菜单,直接进入由default庙宇的操作系统中去,为一可选项.

linux类
其格式一般为:
title (……)
root (hd[0-n],x)
kernel (……)
initrd (……)
其中:
title行,是定义一个启动操作系统,而后边可以自己随便写上喜欢的名字,呵,当然最起码你得写得要自己能认出来,没必要把linux写成windows吧?!

root行,指定相应的linux所有的/boot,如果在写分区和挂载时没有单独挂载,那么就和/在同一个分区中,hd[0-n]表示的是第几个硬盘,而x则表示的是[第几个分区-1],即x比分区号小1,特别要注意.

kernel

行,在这里以kernel 起始,指定Linux的内核的文件所处的绝对路径(通过在终端输入命令:ls

/boot/vmlinuz*来看内核的全名);因为内核是处在/boot目录中的,而如果/boot是独立的一个分区,则需要把boot省略,因为

/boot所在的分区在root (hd[0-n],x)中指定了,所以就无需要再指明内核处在哪个分区了;ro 表示只读;root=LABEL=/

来表示Linux的根所处的分区。LABEL=/

这是硬盘分区格式化为相应文件系统后所加的标签;如果您不了解什么是标签,也可以直接以/dev/hd[a-z]X

或者/dev/sd[a-z]X来表示;就看您的Linux是根分区是在哪个分区了。比如我的是在/dev/hda3,

那这里就可以写成root=/dev/hda3;

initrd行,如果是/boot独立一个分区,initrd

一行要把/boot中省略;如果/boot不是处于一个分区,而是和Linux的/分区处于同一分区,不应该省略;我们通过查看/boot中的

initrd的文件名到底是什么来写这一行代码,在终端输入:ls /boot/initrd*
很容易能得到initrd文件名,然后写入.

在了解了以上情况之后,我们就很容易地理解另一种写法了:
title (……)
kernel (hd[0-n],y)(/boot)…… ro root=……
initrd (hd[0-n],y)(/boot)……
其实只是省略的root很实在地写在了kernel和initrd行中去了而已

附:其实在GRUB启动菜单不能工作的时候,进入GRUB命令行(可按CTRL+C键)后,我们同样可以一步一步地把系统启动起来,其实在menu.lst中,

除title不是指令外,其余的都是GRUB指令,我们只要一步步地输入它们(错了要从新开始),中间输入关于kernel和 initrd要利用
TAB键补齐写好,最后只要boot一下就行了.

用GRUB指令引导windows:
GRUB> rootnoverify (hd0,0)
GRUB> chainloader +1
GRUB> boot

GRUB安全设置
如果希望其他人进入某些系统中来,可以通过给GRUB设置密码实现。设置密码后,如果进入操作系统时就会出现下面信息:
Boting Ubuntu 9.04, kernel 2.6.28-11-generic

lock

Error 32:Must be authenticated

Press any key to continue…
这时候需要按任意健进入到GRUB程序界面,然后再按“p”健输入密码方可进入。
使用grub-md5-crypt命令可以给GRUB设置密码。
kaavield@Ubuntu:~$ grub-md5-crypt
Password:
Retype password:
$!fdfWWo$QxJqS1sSDNcJg1DkZqs$x2
kaavield@Ubuntu:~$ grub-md5-crypt >passwd
kaavield@Ubuntu:~$
使用grub-md5-crypt命令可以产生密码,因为小v要将产生的密码添加到menu.lst文件中,所以可以使用命令重定向将密码保存,设定完密码后将声称的密码添加到menu.lst文件中,添加方式如下:
password –md5 生成的密码值
然后在不想让用户随便进入系统Title下面添加“lock”便可将此系统锁住,这样其他不知道GRUB密码的用户就不能进入相应的操作系统了。
GRUB命令行
GRUB配置文件可能因某些原因出现问题,这样就导致系统后直接进入GRUB的命令行而步伐直接进入操作系统:
=======================================================================
GNU GRUB version 0.97 (638k lower / 16178k upper memory)
[ Minimal BASH-like line editing is supported. For
the first word, TAB lists possible command
completions. Anywhere else TAB lists the possible
completions of a device/filename. ]

grub>

=======================================================================
此时可以通过GRUB命令直接指定操作系统的启动分区和内核文件来启动操作系统。GRUB程序的主要作用就是在系统启动开始找到引导分区和内核文件,因此我们能够直接输入启动和内核文件名,就可以启动操作系统,找到启动分区,在GRUB程序命令行界面中,先进行如下操作:
grub>root (hd
然后按Tab键,这时系统就会提是所有存在的硬盘的引导分区,如果只有一块硬盘,那么肯定就是此盘了,显示如下:
grub>root (hd #Tab
hd0
此是输入0,然后再按两次回车健,将此硬盘的所有分区列出来。
这时要记得自己Ubuntu所安装分区,根据提示,选择所在分区。
这样就指定了Ubuntu系统的启动分区,然后接着指定的内核文件。如果暂时记不清内核文件的名字,则可以通过find命令找到menu.lst文件,查看其写法,(如果此文件也没有了,那么需要自己写一个),使用find命令查找menu.lst文件操作如下:
grub>find /boot/grub #Tab
Possible files are:device.map stage 1 stage2 …..menu.lst
找到此文件后,可用cat命令查看其内容:
grub>cat /boot/grub/menu.lst #Tab
=========================
=……………………………………….=
=..此处显示menu.lst文件内容…=
=========================
此时就可以按照menu.lst文件中内容进行指定内核的操作了,操作如下:
grub>〔此处输入menu.lst文件中的“kernel /boot/vmlinu….”一行再按回车键〕
grub>〔输入menu.lst文件中的”initrd /boot…..”一行〕
grub>boot
在上面输入boot命令后回车即可启动Ubuntu系统了。

设计SNS社区[1]

没有评论

2011 年 01 月 11 日 at 上午 11:00分类:WEB开发

1、需求分析

很多产品经理,一上来又看看开心、看看校内,然后依葫芦画瓢写PRD显然是不对的。每个公司、同样的产品往往研发运营的目的都是不太一样的。所以仿效现成的界面功能是不可取的,所以一定要充分的去听、去听我们自己做社区,以下6点到底是什么样的情况。做到心中有树以后,再开始进行头脑风暴(构思),把抽象的社区的概念形象起来。
1)你得要清楚公司(你们老板)想要做什么样的SNS社区?
2)做这个SNS社区有什么目的?是要做平台,还是要做工具?

3)要做的这个SNS社区,用户定位是哪些群体?

4)要做的这个SNS社区,应该有哪些模块,或要实现哪些功能?

5)要做的这个SNS社区,要与原来的系统结合?原系统底层逻辑是什么样子的?

6)要做的这个SNS社区,产品框架的增资部分或收费部分应该怎么预留或处理?

7)要做的这个SNS社区,公司给我人力、物力,以及项目的战略周期是多长?

2、竞争对手分析
竞争对手分析简单的讲讲,就是同样做社区,有哪些公司在做?有哪些做的比较好?社区A与社区B的差异在哪里?它们的运营数据是怎么样一个情况?和自己定位相近的产品都有哪些?我们的SNS社区差异化优势或竞争优势在哪里?……
通常的就是在自己没有做这个SNS社区通过媒体的调查、用户的调查、第三方数据得到一个综合的报表分析。然后结合自身情况,进行可行性分析,进行自我定位的合理调整。所以和谁比,怎么比,如何比,具体量化到哪个层面都是很重要的。最后公司的领导们也清楚了,自己也清楚了,兄弟们FIRE,开工吧。圆桌会议几轮讨论产品总监、产品经理们接着忙开。

补充一点:很多公司老板就是说要做个什么东西,也没有很明确的概念。很多产品经理就是抄抄改改,最后SNS社区需求写OK了,用户体验的细节也OK了,产品还是缺乏灵魂。当然跟风也没有办法,大家想必也见多了,同时也很无奈,说到底作为执行层大家都是打工的。

3、写需求

不要嫌我啰嗦,上面这么多是为了照顾一些新手。想必大家还是对下面开始的内容感兴趣。

更多内容:点击查看……

ubuntu一开机只有grub> 画面解决办法

没有评论

2011 年 01 月 08 日 at 下午 3:05分类:Linux

grub>root
//看看所在boot分区,可能返回 hd(0,1),那么你台式机一般是/dev/hda1,笔记本一般是/dev/sda1, 现在假设是sda1

grub>linux /boot/vmlinuz(按tab键自动补全) /dev/sda1
//补全后好象是vmlinuz-2.6.**-**-generic记不清楚了

grub>initrd /boot/initrd(tab键自动补全)

grub>boot 启动

进入ubuntu,终端输入 update-grub2

我一个礼拜前也出过这个问题,那时是引导被改写了

2011年Web设计趋势:CSS3+HTML5居首位

没有评论

2011 年 01 月 07 日 at 下午 8:31分类:PHP

在设计和编程之间只有薄薄的一线,当我们进入新的十年时,这条线变得越来越模糊。在Photoshop上绘制漂亮的模型就够了吗?5年以前也许如此。在今天,普通的网络用户要求的更多。所有的东西都很漂亮,但没有实质内容,过段时间人们就会厌烦。如果你唯一的目标是用你漂亮的设计影响圈内其他设计师,你会发现你很快就落伍了。2011年不关心漂亮,而是关心功能。新的一年甚至十年的趋势是交互设计、粘度和虚拟现实。

  2011年你会如何设计呢?设计师的最终目标是留住用户,而不是让人炫目。所有得到惊讶声和赞叹声的设计师都很容易被忘记。高超的设计师可以创造出一种环境,吸引并迷住用户到不想点击”返回”按钮的地步。几个元素汇聚在一起,组成一个奇妙的幻境:和谐的色彩主题、直观的设计、易用的信息和快速的反应。另外,永远不要低估简洁的力量。当然,情况一直如此,但在2011年,你将不再仅针对电脑桌面和笔记本,还要为智能手机、上网本、Tablet等等设计。你准备好了吗?

  看看2011年前11个趋势。
1、更多的CSS3+HTML5

  多么令人满意啊!在过去几年里,CSS3和HTML5只出现在网页设计那遥远的地平线上。但现在,在2011年,我们看到了它的爆发。设计师们终于开始让Flash走开。你可能感觉到,Flash和一些对你当前和潜在用户有用的最新最热技术,配合的不是很好。在2011年,你会慢慢远离Flash,拥抱被称为HTML5的魔术。看看这组惊人相似的比较:

  现在已经显示,Flash和HTML5是不相等的对手。在2011年两者都有大量的应用空间。问题是设计师们在2010年(和之前)滥用了Flash。举一个例子,很少整个网站由Flash组成,特别是这些日子。HTML5减轻了Flash的一些负担。不过,HTML5还不能完全取代我们由Flash实现的那些非凡的设计元素。

  也许更让人兴奋的是,CSS3在今年可以投入使用了。移开Photoshop(哇,Adobe还是不能休息),CSS3可以更快实现文本阴影、圆角边框和背景透明。如果你还没有开始,现在就开始钻研了解CSS3和HTML5吧。

  2、简洁的配色方案

  简洁。没有什么比在安静的背景上显示清晰的消息更安静了。安静可以被解读为几种不同的方式。忘掉黑白和灰度阴影,想想绿色、黄色或甚至红色作为你的主色调。不过,限制你的调色板只有两或三种颜色,试试各种颜色不同的灰度。用少量颜色表现信息是非常了不起的。观察一下:

  绿色阴影创造了这个Twitter可视的工具。边注:这个网站是用XHTML/CSS和Javascript创建的。

  如果做的不好,红色很容易产生冲突。这个网站用高对比的易读文字克服了红色本来的特性。

  3、适用于手机

  智能手机、iPad、上网本,哦天哪!一个令人眼花缭乱的手机产量在2011年提供给消费者。这意味着你的网页设计必须适应多种窗口。

  创建一个适用于手机的网站不是简单的从你的设计中去掉那些花哨的东西。这只会产生一个空虚无个性的设计。虽然不太可能,但从你的原始设计中去掉那些魔法,变成简单陈述你的品牌,这非常困难。幸运的是,技术正在快速解决这些麻烦。

  借助CSS3的帮助,主要是media queries,手机网页设计有一个大的飞跃(以后详说)。最重要的一个进步是,你可以设计一个整站并允许你的编码遵从用户的可视区域。

  设计一个专门的手机网站可能很有诱惑力,但这可能不再能满足你的观众了。越来越多的手机网站包含了访问原始网站的选项。如果你没有提供这一选项或你的原始网站没有为手机标准优化好,你就没有为2011年做好准备。预测显示,智能手机今年的销量将超过个人电脑。准备好你的设计,满足这一需求。

总结2010

没有评论

2011 年 01 月 07 日 at 下午 8:26分类:乱七八糟

2010年的我,变化了很多很多。最大的变化主要有两点,其一是:我的身份发生了巨大的变化,不在是一个在学校里面上学的大学生了,我已经走向社会了,已经成为了一个社会职业者;其二是:之前的我不知道大学毕业我该从事什么我该干什么?但是在今年的年初,我选择了一个目标—-PHP程序员,并为这个目标已经奋斗了一年了;
在这一年里,我从一个对PHP什么都不懂的大学生一直到现在,对PHP慢慢的经历了一年的洗礼,对他慢慢的产生了感情,这一年中也学了PHP不少的东西,但是相对于高手而言,我还是很菜的,这一年中让我知道了很多关于网站方面的知识,这些东西在这之前,我压根就是不知道有他们的存在,自从我开始接触这个PHP以来,所有所有的一切都在发生着潜移默化的改变着,当同学们还在教室里面上课的时候,而我已经走上了南下工作的道路,在同学们还在暑假里面享受暑假的欢快时,而我却在不断的写着程序。这一年的暑假时大二的暑假,也是大学的最后一个暑假,也是我人生中第一个没有假期的暑假,因为我要工作!每当我回到我的大学校园时,总有那么点亲切感,虽然我只在那个地方呆了一年半的时间,感觉那就是我在合肥的一个家。
这一年里,在技术上面的成绩就是从无到有的那么一年,这一年里面我学会了很多,这个很多包括看的到的和看不到,从对PHP的;零技术到现在的能力和水平,可以说是,对于我自己而言是一个很大的成绩,以及相关的技术上面的提高,对于我来说都是一个很不错的提高,但是我现在还是不能和那些老鸟相比的,也是没法比的!这一点我自己心知杜明。在这一年当中我拼命的学,拼命的往自己的头脑里面灌东西,拼命的想提高自己的能力和技术水平,因此我个人感觉这一年我过的还是蛮充实的,蛮实在的。
在温州工作的这半年时间,着实让我学到了不少东西,认识了社会上各种利害关系的存在,认识了人与人之间的利益交往,认识了只有高技术,高水平的人才能被人们看得起,才能被老板亲莱。认识到了社会上勾心斗角的事情时有发生。。。。。。。在社会上你永远也不能说你完全了解一个人。。。
只有当你走向社会了才知道社会的压力原来是那么的大,是那么的重,压的我们这些稚嫩的肩膀都挺不起来了!面对着社会上种种的压力,我们没有办法,我们只有咬紧牙,不断的努力,不断的充实自己的能力,不断地额提高自己的社会的阅历。。。在这个信息超级爆炸的时代,我们随时都有可能被这个社会残忍的所抛弃,我们只有自己救自己。我们不是富二代,你爸也不是李刚,我们需要我们自己去努力……
对于2010是我人生的一个重大转折点。当然这是个好的转折点,也是我所向往的……2010已经过去了,不管在过去的一年中我们经历了什么,不管是痛苦,还是愉快,那已成为历史。我们需要一颗倘然的心去面对过去的喜怒哀乐,我们更需要一颗充满激情与踌躇的心去面对2011,因为它现在还是一张白纸,你的那一部分正在等在你去描绘。我们要相信自己……
对于自己,在2011年,将会换一个工作环境。年轻人嘛,就是需要到处闯闯。不断的积累自己的社会经验和社会阅历,在2011年关于技术方面,希望自己能有一个质的提高,在新的一年里,希望自己还是能够坚持不懈,不断的努力去奋斗。。。。
最后,祝福自己,也祝福所有的人……

js实现cookie

没有评论

2011 年 01 月 07 日 at 下午 7:42分类:JavaScript | WEB开发

构造通用的cookie处理函数 cookie的处理过程比较复杂,并具有一定的相似性。因此可以定义几个函数来完成cookie的通用操作,从而实现代码的复用。下面列出了常用的cookie操作及其函数实现。
1.添加一个cookie:addCookie(name,value,expireHours) 该函数接收3个参数:cookie名称,cookie值,以及在多少小时后过期。这里约定expireHours为 0时不设定过期时间,即当浏览器关闭时cookie自动消失。该函数实现如下:

 <script language="JavaScript" type="text/javascript"> 
<!-- function addCookie(name,value,expireHours){ 
var cookieString=name+"="+escape(value); 
//判断是否设置过期时间
 if(expireHours>0){ 
var date=new Date(); 
date.setTime(date.getTime+expireHours*3600*1000); 
cookieString=cookieString+"; 
expire="+date.toGMTString(); 
} 
document.cookie=cookieString; 
} //--> 
</script> 

2.获取指定名称的cookie值:getCookie(name) 该函数返回名称为name的cookie值,如果不存在则返回空,其实现如下:

<script language="JavaScript" type="text/javascript"> 
<!-- function getCookie(name){ 
var strCookie=document.cookie; 
var arrCookie=strCookie.split("; "); 
for(var i=0;i<arrCookie.length;i++){ 
var arr=arrCookie[i].split("=");
 if(arr[0]==name)return arr[1]; 
} return "";
 } //--> 
</script> 

3.删除指定名称的cookie:deleteCookie(name) 该函数可以删除指定名称的cookie,其实现如下:

<script language="JavaScript" type="text/javascript"> 
<!-- function deleteCookie(name){ 
var date=new Date(); 
date.setTime(date.getTime()-10000); 
document.cookie=name+"=v;
 expire="+date.toGMTString(); 
} //-->
 </script>

PHP进制之间的转换函数详解

没有评论

2011 年 01 月 07 日 at 下午 7:36分类:PHP

一,十进制(decimal system)转换函数说明

1,十进制转二进制 decbin() 函数,如下实例

echo decbin(12); //输出 1100
echo decbin(26); //输出 11010

decbin
(PHP 3, PHP 4, PHP 5)
decbin — 十进制转换为二进制
说明
string decbin ( int number )
返回一字符串,包含有给定 number 参数的二进制表示。所能转换的最大数值为十进制的 4294967295,其结果为 32 个 1 的字符串。
2,十进制转八进制 decoct() 函数

echo decoct(15); //输出 17
echo decoct(264); //输出 410

decoct
(PHP 3, PHP 4, PHP 5)
decoct — 十进制转换为八进制
说明
string decoct ( int number )
返回一字符串,包含有给定 number 参数的八进制表示。所能转换的最大数值为十进制的 4294967295,其结果为 “37777777777″。
3,十进制转十六进制 dechex() 函数

echo dechex(10); //输出 a
echo dechex(47); //输出 2f

dechex
(PHP 3, PHP 4, PHP 5)
dechex — 十进制转换为十六进制
说明
string dechex ( int number )
返回一字符串,包含有给定 number 参数的十六进制表示。所能转换的最大数值为十进制的 4294967295,其结果为 “ffffffff”。

二,二进制(binary system)转换函数说明
1,二进制转十六制进 bin2hex() 函数

$binary = "11111001";
$hex = dechex(bindec($binary));
echo $hex;//输出f9

bin2hex
(PHP 3 >= 3.0.9, PHP 4, PHP 5)
bin2hex — 将二进制数据转换成十六进制表示
说明
string bin2hex ( string str )
返回 ASCII 字符串,为参数 str 的十六进制表示。转换使用字节方式,高四位字节优先。
2,二进制转十制进 bindec() 函数

echo bindec('110011'); //输出 51
echo bindec('000110011'); //输出 51
echo bindec('111'); //输出 7

bindec
(PHP 3, PHP 4, PHP 5)
bindec — 二进制转换为十进制
说明
number bindec ( string binary_string )
返回 binary_string 参数所表示的二进制数的十进制等价值。
bindec() 将一个二进制数转换成 integer。可转换的最大的数为 31 位 1 或者说十进制的 2147483647。PHP 4.1.0 开始,该函数可以处理大数值,这种情况下,它会返回 float 类型。

三,八进制(octal system)转换函数说明
八进制转十进制 octdec() 函数

echo octdec('77'); //输出 63
echo octdec(decoct(45)); //输出 45

octdec
(PHP 3, PHP 4, PHP 5)
octdec — 八进制转换为十进制
说明
number octdec ( string octal_string )
返回 octal_string 参数所表示的八进制数的十进制等值。可转换的最大的数值为 17777777777 或十进制的 2147483647。PHP 4.1.0 开始,该函数可以处理大数字,这种情况下,它会返回 float 类型。

四,十六进制(hexadecimal)转换函数说明
十六进制转十进制 hexdec()函数

var_dump(hexdec("See"));
var_dump(hexdec("ee"));
// both print "int(238)"
var_dump(hexdec("that")); // print "int(10)"
var_dump(hexdec("a0")); // print "int(160)"

hexdec
(PHP 3, PHP 4, PHP 5)
hexdec — 十六进制转换为十进制
说明
number hexdec ( string hex_string )
返回与 hex_string 参数所表示的十六进制数等值的的十进制数。hexdec() 将一个十六进制字符串转换为十进制数。所能转换的最大数值为 7fffffff,即十进制的 2147483647。PHP 4.1.0 开始,该函数可以处理大数字,这种情况下,它会返回 float 类型。
hexdec() 将遇到的所有非十六进制字符替换成 0。这样,所有左边的零都被忽略,但右边的零会计入值中。

五,任意进制转换 base_convert() 函数

$hexadecimal = 'A37334';
echo base_convert($hexadecimal, 16, 2);//输出 101000110111001100110100

base_convert
(PHP 3 >= 3.0.6, PHP 4, PHP 5)

base_convert — 在任意进制之间转换数字
说明
string base_convert ( string number, int frombase, int tobase )
返回一字符串,包含 number 以 tobase 进制的表示。number 本身的进制由 frombase 指定。frombase 和 tobase 都只能在 2 和 36 之间(包括 2 和 36)。高于十进制的数字用字母 a-z 表示,例如 a 表示 10,b 表示 11 以及 z 表示 35。

判断php运行环境的函数php_sapi_name()

没有评论

2011 年 01 月 07 日 at 下午 7:32分类:PHP

我们一般情况下,都是在apache下面运行我们的php程序,当然也有些人是用IIS环境的
我们要是想知道我们目前运行的环境是什么的话,那我们可以用函数php_sapi_name()来测试
代码:

<?php
echo php_sapi_name();

在apache环境下面输出的结果是“apache2handler”;
在cgi模式下输出的结果是“cgi-fcgi”
要是在命令行模式下面运行的话,那么输出的结果是:”cli”
依据这个内容我们可以判断当前运行的环境是什么!
那么在命令行下怎么运行呢?
如下:
进入DOS 进入php.exe文件的地址 如我的是:d:/wamp/bin/php/php5.3.3/
然后输入php.exe “文件的绝对路径” 如:>php.exe d:/wamp/www/info.php
既可以了。

<?php
if(substr(PHP_SAPI_NAME(),0,3) !== 'cli'){
	die("该程序只能在CLI模式下运行!");
}
//print_r(get_defined_constants());

Class Test{
	public $name = "";
	public $value = "";
	public $content = "";
	public $arr = array();

	public function __construct(){
		$this->top();
	}

	public function top(){
		fwrite(STDOUT,"请输入参数和值:");
		$this->content = trim(fgets(STDIN));
		preg_replace('/\s+/',' ',$this->content);
		$this->arr = explode('->',$this->content);
		$this->name = $this->arr['0'];
		$this->value = $this->arr['1'];
	}

	public function ouput(){
		echo "=========================================
| THE NAME  |  .$this->name
 =========================================
| THE VALUE |  '.$this->value;
 =========================================\n";
	}

}
while(true){
	$t = new Test();
	$t->ouput();
}