PHP学习练手(十五)


阻止垃圾邮件


一、垃圾邮件的预防技术

  1. 使用正则表达式或过滤器扩展验证任何电子邮件地址

  2. 在表单值中监视这些字符。如果值中包含该列表中的任何内容,就不要使用那个值。
    这里写图片描述

    2.1 代码:
    email2.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Contact Me</title>
</head>
<body>
    <h1>Contact Me</h1>
    <?php

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

            //函数功能是实现字符过滤
            function spam_scrubber($value)
            {
                $very_bad = array('to', 'cc:', 'content-type:', 'mime-version:','multipart-mixed:','content-transfer-encoding');

                //判断$value中是否存在$very_bad中包含的各种变量
                foreach($very_bad as $v)
                {
                    if(stripos($value, $v) != false)
                    {
                        return '';
                    }
                }

                //字符串替换
                $value = str_replace(array("\r", "\n", "%0a", "%0d" ), '', $value);

                //过滤空格
                return trim($value);
            }

            //将函数作用到数组的每个值上
            $scrubbed = array_map('spam_scrubber', $_POST);

            if(!empty($scrubbed['name']) && !($scrubbed['email']) && !empty($scrubbed['comments']))
            {
                $body = "Name: {$scrubbed['name']}\n\nComments: {$scrubbed['comments']}";

                //字符截断
                $body = Wordwrap($body, 70);

                mail('[email protected]', 'Contact From Submission', $body, "From:{$_POST['email']}");

                echo '<p><em>Thank you for contacting me. I will reply some day.</em></p>';

                $_POST =array() ;	//将$_POST清空
            }else{
                echo '<p style="font-weight: bold; color: #C00"></p>';
            }
        }
    ?>
    <p>Please fill out this form to contact me.</p>
    <form action="email.php" method="post">
        <p>Name: <input type="text" name="name" size="30" maxlength="60" value="<?php if(isset($_POST['name'])) echo $_POST['name']; ?>" /></p>
        <p>Email Address: <input type="text" name="name" size="30" maxlength="80" value="<?php if(isset($_POST['email'])) echo $_POST['email']; ?>" /></p>
        <p>Comments: <textarea name="comments" rows="5" cols="30"><?php if(isset($_POST['comments'])) echo $_POST['comments']; ?></textarea></p>
        <p><input type="submit" name="submit" value="Send!" /></p>
    </form>
</body>
</html> 

2.2 函数解析:

stripos():函数查找字符串在另一字符串中第一次出现的位置(不区分大小写)。

str_replace():函数以其他字符替换字符串中的一些字符(区分大小写)。

array_map():将函数作用到数组中的每个值上,每个值都乘以本身,并返回带有新值的数组。

2.3代码解析:

$very_bad = array('to', 'cc:', 'content-type:', 'mime-version:','multipart-mixed:','content-transfer-encoding');

                //判断$value中是否存在$very_bad中包含的各种变量
                foreach($very_bad as $v)
                {
                    if(stripos($value, $v) != false)
                    {
                        return '';
                    }
                }

解释: $very_bad 存储了所有可能的不合法联系人字符。foreach循环一次将访问$very_bad 中的一个数据项,stripos()函数将检查作为$value 提供给该函数的数据项是否存在字符串中。一旦发现“危险”字符串,函数将返回一个空字符串并终止运行。

2.4 代码运行:
这里写图片描述
注:由于提交的Email Address中出现了不合法字符,因此,该邮件不会被发送。


通过类型验证数据


一、2种验证方法:
- 白名单:设置能通过的用户,白名单以外的用户都不能通过
- 黑名单:设置不能通过的用户,黑名单以外的用户都能通过。

1.1 代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Widget</title>
</head>
<body>
    <?php # Script 13.2 - calculator.php
        if($_SERVER['REQUEST_METHOD']=='POST')
        {
            $quantity = (int) $_POST['quantity'];
            $price = (float) $_POST['price'];
            $tax = (float) $_POST['tax'];

            if(($quantity > 0) && ($price > 0) && ($tax > 0))
            {
                $total = $quantity * $price;
                $total += $total * ($tax/100);

                echo '<p>The cost of purchasing '.$quantity.' widget(s) at $'.number_format($price, 2).'each, plus tax, is $'.number_format($total, 2).'</p>';
            }else{
                echo '<p style = "font-weight: bold; color: #C00">Please enter a valid quantity, price, and tax rate.</p>';
            }
        }


    ?>
    <h1>Widget Cost Calculator</h1>
    <form action="calculator.php" method="post">
        <p>Quantity: <input type="text" name="quantity" size="5" maxlength="10" value="<?php if(isset($quantity)) echo $quantity; ?>" /></p>
        <p>Price: <input type="text" name="price" size="5" maxlength="10" value="<?php if(isset($price)) echo $price; ?>" /></p>
        <p>Tax: <input type="text" name="tax" size="5" maxlength="10" value="<?php if(isset($tax)) echo $tax; ?>" /></p>
        <p><input type="submit" name="submit" value="Calculate" /></p>
    </form>
</body>
</html>

1.2 代码解释:

$quantity = (int) $_POST['quantity'];
            $price = (float) $_POST['price'];
            $tax = (float) $_POST['tax'];

解释:通过强制转换变量类型,验证数据的正确格式

1.3 代码运行:
这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述


按类型验证文件


1、$_FILES['upload']['type'] 是指上传浏览器提供的MIME类型。但是恶意用户很容易通过提供虚假的MIME类型诱骗浏览器

2、Fileinfo是在服务器端进行内容类型的检验。Fileinof通过获取文件的“魔法字节”或“魔法数字”来判断文件的类型(和编码),例如,构成GIF图片的数据必须以ASCII码GIF89a或GIF87a开头,构成PDF文件的数据必须以%PDF开头。

3、如何使用Fileinfo:

  • 要使用Fileinfo,首先创建Fileinfo资源: $fileinfo = finfo_open(kind) kind值是个常量,指定创建的资源类型,判断文件类型的常量是FILEINFO_MIME_TYPE,即$file = finfo_open(FILEINFO_MYIME_TYPE)

  • 接下来,调用finfo_file()函数,提供Fileinfo资源和要检查的文件的引用finfo_file($fileinfo, $filename) 此函数基于文件的实际“魔法字节”,返回文件的MIME类型(已经创建的资源)

  • 完成后,应关闭Fileinfo的资源finfo_close($fileindo)

4、代码upload_rtf.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Upload a  RTF Document</title>
</head>
<body>
    <?php # Script 13.3 - upload_rtf.php
        if($_SERVER['REQUEST_METHOD'] == 'POST')
        {

            if(isset($_FILES['upload']) && file_exists($_FILES['upload']['tmp_name']))
            {
                //创建fileinfo资源
                $fileinfo = finfo_open(FILEINFO_MIME_TYPE);
                //服务器端检查文件类型
                if(finfo_file($fileinfo, $_FILES['upload']['tmp_name']) == 'text/rtf')
                {
                    echo '<p><em>The file would be acceptable</em></p>';
                    //删除临时文件
                    unlink($_FILE['upload']['tmp_name']);
                }else{
                    echo '<p style = "font-weight: bold; color: #C00">Please upload an RTF document.</p>';
                }
                //关闭Fileinfo资源
                finfo_close($fileinfo);
            }
        }
    ?>
    <form enctype="multipart/form-data" action="upload_rtf.php" method = "post">
        <input type="hidden" name="MAX_FILE_SIZE" value="524288" />
        <fieldset>
            <legend>Select an RTF document of 512KB or smaller to be uploaded</legend>
            <p><b>File:</b> <input type="file" name="upload"/></p>
            <div align="center"><input type="submit" name="submit" value="Submit"></div>
        </fieldset>

    </form>
</body>
</html>

这里写图片描述

这里写图片描述


阻止XSS攻击


1、XSS(跨站脚本)攻击——

许多动态驱动的web应用程序会获取用户提交的信息,将其存储在数据库中,然后在另一个页面上重新显示该信息。当用户在数据中输入HTML代码,这种代码就可能抛弃站点的布局和美感。更糟糕的是,JS也只是纯文本,但它是Web浏览器内可执行的脚本,可能会造成弹窗,窃取cookie或者把浏览器重定向到其他站点,称之为XSS攻击。

2、代码:
xss.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>XSS Attacks</title>
</head>
<body>
    <?php # Script 13.4 - xss.php
        if($_SERVER['REQUEST_METHOD'] == 'POST')
        {
            echo "<h2>Original</h2><p>{$_POST['data']}</p>";
            echo '<h2>After htmlspecialchars() </h2><p>'.htmlspecialchars($_POST['data']).'</p>';
            echo '<h2>After htmlentities() </h2><p>'.htmlentities($_POST['data']).'</p>';
            echo "<h2>After strip_tags() </h2><p>".strip_tags($_POST['data'])."</p>";
        }
    ?>
    <form action="xss.php" method="post">
        <p>Do your worst!<textarea name="data" cols="40" rows="4"></textarea><div><input type="submit" name="submit" value="Submit" /></div>
        </p>
    </form>
</body>
</html>

3、函数解析:

  • htmlspecialchars():把预定义的字符转换为 HTML 实体

  • htmlentities():把字符转换为 HTML 实体

  • strip_tags():去掉字符串中的 HTML 标签

  • 这3个函数以从破坏性最小到最大的顺序列出。

4、代码运行:
这里写图片描述

这里写图片描述


使用过滤器扩展


1、过滤器扩展的目的——验证数据或清理数据

2、使用函数filter_var(variable, filter[,options])

3、过滤器选择
这里写图片描述

4、代码:
calculator2.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Widget</title>
</head>
<body>
    <?php # Script 13.2 - calculator.php
        if($_SERVER['REQUEST_METHOD']=='POST')
        {
            //$quantity = (int) $_POST['quantity'];
            //$price = (float) $_POST['price'];
            //$tax = (float) $_POST['tax'];

            //如果是整数则保存,否则为null
            $quantity = (isset($_POST['quantity'])) ? filter_var($_POST['quantity'], FILTER_VALIDATE_INT, array('min_range'=>1)) : NULL;
            //如果是浮点数,则保存,否则为null
            $price = (isset($_POST['price'])) ? filter_var($_POST['price'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : NULL;
            $tax = (isset($_POST['tax'])) ? filter_var($_POST['tax'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION) : NULL;

            if(($quantity > 0) && ($price > 0) && ($tax > 
                0))
            {
                $total = $quantity * $price;
                $total += $total * ($tax/100);

                echo '<p>The cost of purchasing '.$quantity.' widget(s) at $'.number_format($price, 2).'each, plus tax, is $'.number_format($total, 2).'</p>';
            }else{
                echo '<p style = "font-weight: bold; color: #C00">Please enter a valid quantity, price, and tax rate.</p>';
            }
        }


    ?>
    <h1>Widget Cost Calculator</h1>
    <form action="calculator2.php" method="post">
        <p>Quantity: <input type="text" name="quantity" size="5" maxlength="10" value="<?php if(isset($quantity)) echo $quantity; ?>" /></p>
        <p>Price: <input type="text" name="price" size="5" maxlength="10" value="<?php if(isset($price)) echo $price; ?>" /></p>
        <p>Tax: <input type="text" name="tax" size="5" maxlength="10" value="<?php if(isset($tax)) echo $tax; ?>" /></p>
        <p><input type="submit" name="submit" value="Calculate" /></p>
    </form>
</body>
</html>

5、代码运行
这里写图片描述

这里写图片描述

这里写图片描述


预防SQL注入攻击


1、SQL注入攻击——是指企图把不良代码插入到站点SQL查询中。这类攻击的目标之一是,它们将创建一个语法上无效的查询,从而再得到的出错消息中呈现关于脚本或数据库的某些消息。而注入攻击更大的目的是改变、破坏或暴露存储的数据。

2、预处理语句的性能
预处理语句比老式的查询方式更安全,而且可能也会更快。如果一个PHP脚本多次发送相同的PHP查询到MySQL,每次使用不同的值,预处理可以加快速度。在这种情况下,只会把查询本身发送给MySQL,并且只会解析一次。然后,单独把值发送给MySQL。

3、如果不使用预处理语句,整个查询(包括SQL语法和具体的值)都会作为一个长字符串发送到MySQL。然后MySQL分析并执行它。使用预处理查询,SQL语法首先被发送到MySQL解析,确保它在语法上是有效的,然后单独发送特定的值,MySQL使用这些值组合查询,然后执行它。

4、预处理的优点:它可以带来更高的安全性、并且可能提供更好的工作的性能。

5、代码:
post_message.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Post a message</title>
</head>
<body>
    <?php # Script 13.6 - post_message.php
        if($_SERVER['REQUEST_METHOD'] == 'POST')
        {
            $mysqli = mysqli_connect('localhost', 'root', '1111', 'forum');

            $sql = "INSERT INTO messages(forum_id, parent_id, user_id, subject, body, date_entered) VALUES (?,?,?,?,?, NOW())";
            $stmt = mysqli_prepare($mysqli, $sql);
            mysqli_stmt_bind_param($stmt, 'iiiss', $forum_id, $parent_id, $user_id, $subject, $body);
            $forum_id = (int) $_POST['forum_id'];
            $parent_id = (int) $_POST['parent_id'];
            $user_id = 3;
            $subject = strip_tags($_POST['subject']);
            $body = strip_tags($_POST['body']);
            mysqli_stmt_execute($stmt);

            if(mysqli_stmt_affected_rows($stmt) == 1){
                echo '<p>Your messages has been posted.</p>';
            }else{
                echo '<p style="font-weight: bold; color: #C00">Your message could not be posted.</p>';
                echo '<p>'.mysqli_stmt_error($stmt).'</p>';
            }

            mysqli_stmt_close($stmt);
            mysqli_close($mysqli);
        }
    ?>
    <form action="post_message.php" method="post">
        <fieldset>
            <legend>Post a message</legend>
            <p><b>Subject</b>: <input type="text" name="subject" size="30" maxlength="100" /></p>
            <p><b>Body</b>: <textarea name="body" cols="40" rows="4"></textarea></p>
            <div align="center"><input type="submit" name="submit" value="Submit"></div>
        </fieldset>
        <input type="hidden" name="forum_id" value="1" />
        <input type="hidden" name="parent_id" value="0" />
    </form>
</body>
</html>

6、代码解析:

  • $sql = "INSERT INTO messages(forum_id, parent_id, user_id, subject, body, date_entered) VALUES (?,?,?,?,?, NOW())"; //预处理sql语句

  • $stmt = mysqli_prepare($mysqli, $sql); //将结果写入到对应的数据库变量中

  • mysqli_stmt_bind_param($stmt, 'iiiss', $forum_id, $parent_id, $user_id, $subject, $body); //绑定对应的参数,‘iiiss’表示第1,2, 3是整数 第4,5是字符串等类型

  • mysqli_stmt_execute($stmt);//执行预处理语句

  • mysqli_stmt_close($stmt);//关闭预处理资源

7、代码运行
这里写图片描述

这里写图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章