一个理由PHP.Is无处不在是因为它的语言让一个简单的应用程序很容易启动和运行。许多在线教程演示了如何编写一个数据库应用程序的基础知识,您可以快速适应您的特定需求。

但是要小心!这个优点也可能是PHP的一大弱点。因为PHP让创建工作程序变得如此容易,所以对于没有经验的程序员来说,编写缓慢、难以维护和充满安全漏洞的代码也同样容易。太多的PHP程序员在编写看似正常的代码,但实际上却充满了潜在的危险和维护问题。

这篇文章是写给他们的。

为帮助,让我们贯穿四个PHP脚本来执行一个简单的任务:将用户的名称和年龄保存到MySQL数据库。

每个示例将是之前的一个改进。如果您只是学习PHP,则1级示例可能看起来像你知道如何做的事情,但它很危险,应该得到改善。接下来的三个例子旨在为您提供如何编写更安全,更容易维护的代码的更好的想法。只要记住,这种编码技术的进展就是一种高级概述,而不是PHP中数据库使用的引用。你会想要的阅读PHP手册的。

1级:基本MySQL,打开错误和SQL注入

让我们看一个简单的表单,它允许用户在表单中输入他们的名字和电子邮件地址,这样你的PHP程序就可以把它写到一个数据库表中:

  条目表单#1 </ title> </ head> <body> <form方法=“post”action =“post1.php”>名称:<输入名称=“name”类型=“文本”> <br />年龄:<输入名称=“age”类型=“text”> <br /> <输入类型=“提交”值=“保存”> </ form> </ body> </HTML></pre>
              <p>现在,这是一个PHP脚本,它从用户中取出该输入并将其写入MySQL数据库:</p>
              <pre><code class="PHP"><?php $ servername ='localhost';$ username =“秘密”;密码=美元“秘密”;美元dbname = '用户;$ name = $ _POST['名字'];$年龄= $ _POST['年龄'];// ... //验证$ ysge作为空间省略的有效数字。// ... $ conn = mysql_connect($ servername,$ username,$密码);$ db = mysql_select_db($ dbname,$ conn);如果(!$ db){die(“不能使用db $ dbname”。mysql_error()); } $result = mysql_query( "INSERT INTO users ( name, age ) VALUES ( '$name', $age )" ); if ( !$result ) { die( 'ERROR: ' . mysql_error() ); } ?></code></pre>
              <p>这是PHP中数据库交互的基本方法。您可能在2000年代初的PHP上的旧书中找到这样的代码,或网站上的快速和肮脏的教程。</p>
              <p><em>(请注意,我们的一个字段是一个数字。我省略了对该字段的任何验证,例如确保字段实际上是一个数字值,而不是例如字符串“十二”,或者年龄不是负数。这很重要,但在本文的范围之外。</em><a href="https://secure.php.net/manual/en/function.is-numeric.php" target="_blank"><em>这<code>is_numeric</code>功能</em></a><em>是起点。类似地,在SQL中也不引用数值。您的数据库可能会宽恕并将字符串'12'转换为数字值12,但是正确的方法是不引出数值值。)</em></p>
              <p>此页面的初始版本有效,似乎有意义。您可以了解PHP代码的部分如何组合在一起,并且可以清楚将数据从用户组装到将数据放入数据库中的SQL语句。你已经工作了,你满意你有一些良好的工作代码。</p>
              <p>然而,这种形式是编码相当于攀爬摇摇欲坠的阶梯。让我们来看看一些最危险的元素。</p>
              <h3>问题字符,安全性和逃避您的数据</h3>
              <p>首先,第一个版本使用旧的<code>mysql_xxx</code>功能。这些已被推翻支持更新<a href="https://secure.php.net/manual/en/book.mysqli.php" target="_blank"><code>mysqli_xxx</code>职能</a>。这意味着在未来的释放中,<code>mysql_xxx</code>函数可能会消失,您的代码可以停止工作。</p>
              <p>其次,您的SQL可能会在某些情况下爆炸;例如,如果数据字段具有撇号。如果有人在名称字段中进入“Catherine O'Leary”,则结果的SQL代码将如下所示:</p>
              <pre><code class="SQL">INSERT INTO users (name, age) VALUES ('Catherine O' leary ', 37);</code></pre>
              <p>这将产生以下错误:</p>
              <pre>错误:您的SQL语法中有错误;检查对应于MySQL Server版本的手册,以便在第1行附近使用近的“Leary”,“')”</pre>
              <p>字符串值<code>“凯瑟琳奥尔雅</code>由于撇号界定的字符串中间的撇号不是一个有效的字符串。SQL Interpreter认为字符串在此之后停止<code>O.</code>。为了使程序在字符串中间接受撇号,它必须通过反斜杠之前“逃脱”,因此它如下所示:</p>
              <pre><code class="SQL">插入用户(名称,年龄)值('凯瑟琳o \'Leary',37);</code></pre>
              <p>要转义字符串,可以使用PHP函数<code>str_replace</code>用反斜杠序列替换单引号,但要使用更好的方法<code>mysql_real_escape_string.</code>为你做这件事。只是确保使用<code>mysql_real_escape_string.</code>并不是<a href="https://stackoverflow.com/questions/3665572/mysql-escape-string-vs-mysql-real-escape-string" target="_blank">旧,弃用<code>mysql_escape_string.</code>,这没有基于字符集逃脱字符串</a>。</p>
              <p>逃避你的琴弦是另一种更重要的原因。从互联网中不受信任的数据构造的SQL代码是一个巨大的安全问题,易于“SQL注入”。您正在编写的SQL代码可以使用Web上的任何人的数据。您正在执行至少部分地构建的代码,这些代码是潜在恶意的东西。黑客可以在SQL命令中嵌入其他SQL代码,并窃取您的数据或接管您的服务器。</p>
              <p>您可能会看到代码使用各种其他PHP函数来处理转义;这通常也是一个错误。例如,您可能会看到一些程序员使用<code>str_replace</code>或者<code>addslashes</code>,但特定于数据库的函数是去的方式。数据库功能涵盖边缘案例您可能不知道特定于您的数据库,并且还考虑到帐户字符编码。您可能会看到人们使用用于处理HTML数据的功能,例如<code>htmlspecialchars.</code>或者<code>而且不会</code>但是,但HTML编码和数据库编码完全无关。HTML的编码与SQL语句的编码不同,因此如果使用HTML函数使用用于数据库编码,则会获取错误的结果。</p>
              <h3>等级2:用mysqli手动逃脱数据</h3>
              <p>现在,让我们来看看代码的第二个版本,使用mysqli并正确转义:</p>
              <pre><code class="PHP"><?php $ servername ='localhost';$ username =“秘密”;密码=美元“秘密”;美元dbname = '用户;$ name = $ _POST['名字'];$年龄= $ _POST['年龄'];// $age的验证被省略。$mysqli = new mysqli($username, $password, $dbname);如果(mysqli_connect_errno()) {die('连接失败:'。mysqli_connect_error ()); } $escaped_name = $mysqli->real_escape_string( $name ); if ( !$mysqli->query( "INSERT INTO users ( name, age ) VALUES ( '$escaped_name', $age )" ) ) { die( 'ERROR: ' . $mysqli->error ); } ?></code></pre>
              <h3>准备好陈述的力量</h3>
              <p>此版本使用较新的<code>mysqli</code>延伸而不是<code>mysql.</code>扩展名,它适当地逃脱输入以防止错误和SQL注入攻击。</p>
              <p>如果这是您要编写的唯一代码,那么您可以这样保留它,一切都会很好。但是,在SQL语句中处理数据转义和格式化容易导致程序员出错。如果忘记转义某些数据怎么办?没有人想要处理引用字符串数据而不引用数字数据。幸运的是,有一种更简单的方法:使用准备好的语句和占位符。</p>
              <p>准备好的语句比调用普通的old语句需要更多的PHP代码行<code>mysqli_query.</code>,但它们更安全,重复呼叫可以更快地执行。</p>
              <p>当您准备SQL语句时,数据库将处理SQL并准备执行,但它实际上并不执行数据库中的任何代码。这可以在反复执行相同的SQL查询时提高速度,因为查询只需准备一次,然后执行多次,而不是同时准备和执行多次。</p>
              <p>预备语句最重要的优点是允许使用值占位符或绑定变量。这允许您将SQL语句与它将要操作的数据分离。这可以使您的SQL更容易理解,并防止SQL注入而不必自己转义数据。</p>
              <h3>第3级:使用MySQLI准备的陈述</h3>
              <p>让我们看看这些准备好的语句的实际效果:</p>
              <pre><code class="PHP"><?php $ servername ='localhost';$ username =“秘密”;密码=美元“秘密”;美元dbname = '用户;$ name = $ _POST['名字'];$年龄= $ _POST['年龄'];// $age的验证被省略。$mysqli = new mysqli($username, $password, $dbname);如果(mysqli_connect_errno()) {die('连接失败:'。mysqli_connect_error ()); } $stmt = $mysqli->prepare( 'INSERT INTO users ( name, age ) VALUES ( ?, ? )' ); if ( !$stmt ) { die( 'ERROR: ' . $mysqli->error ); } $stmt->bind_param( 'si', $name, $age ); if ( !$stmt->execute() ) { die( 'ERROR: ' . $mysqli->error ); } ?></code></pre>
              <p>注意在此版本中,查询根本无法从变量构建。它是由程序员创建的单个字符串,其中包含占位符(问号),告诉PHP,其中在执行查询时的值将会发生。外部数据无法删除此SQL查询是不可能的,因为查询的文本未使用任何外部数据构建。</p>
              <p>这<code>bind_param.</code>然后,方法允许您指定每个占位符的值:</p>
              <pre><code class="PHP">$ stmt-> bind_param('si',$ name,$ age);</code></pre>
              <p>这<code>“如果”</code>意味着在该顺序中有两个参数,字符串和整数。您必须确保您的占位符和值匹配。</p>
              <p>占位符在SQL语句中从未引用过。他们展示了一个值将要去的地方,并且每个值的类型由呼叫确定<code>bind_param.</code>。</p>
              <p>只有当语句真正被执行时<code>执行()</code>外部数据是否参与其中。中指定的变量的数据<code>bind_param.</code>直接传递给数据库,而不必转换为SQL语句。</p>
              <h3>用pdo抽象</h3>
              <p>让我们通过介绍PDO包来将我们的计划带到第三级。PDO代表<a href="http://php.net/manual/en/intro.pdo.php" target="_blank">PHP数据对象</a>,并使调用数据库更容易,但虽然更容易。PDO还简化了绑定参数的处理。</p>
              <p>PDO的另一个优点是它没有与特定的数据库系统相关联。使用我们的旧版本,如果我们想将数据库从MySQL更改为PostgreSQL,我们必须更改所有代码<code>mysqli_xxx</code>打电话<code>pg_xxx.</code>功能。使用PDO,数据库之间的那些差异就被抽象掉了。要找出你的系统已经安装的PDO驱动程序,使用以下代码:</p>
              <pre><code class="PHP">print_r (PDO: getAvailableDrivers ());</code></pre>
              <p>在我的系统上显示:</p>
              <pre>数组([0] => mysql [1] => pgsql [2] => sqlite)</pre>
              <p>如果在系统上运行该系统时未显示要使用的数据库系统,则需要为其安装驱动程序。</p>
              <h3>4级:使用PD编写报表<strong>O.</strong></h3>
              <p>PDO版本所做的事情与我们之前看到的略有不同:</p>
              <pre><code class="PHP"><?php $ servername ='localhost';$ username ='scratch';$ password ='scratch';$ dbname ='scratch';$ name = $ _POST['名字'];$年龄= $ _POST['年龄'];// $age的验证被省略。尝试{$ dbh = new pdo(“mysql:host = $ servername; dbname = $ dbname”,$ username,$ password);$ sth = $ dbh->准备('插入用户(名称,年龄)值(:姓名,:年龄)');$ sth-> bindparam(':name',$ name,pdo :: param_str); $sth->bindParam( ':age', $age, PDO::PARAM_INT ); $sth->execute(); } catch( PDOException $e ) { die( 'Failed: ' . $e->getMessage() ); } ?></code></pre>
              <p>首先,注意所有要做的工作都在里面<code>尝试</code>块,然后是一个<code>抓</code>块。这使我们免于检查每一个操作的成功或失败。如果该块内的任何语句失败,PDO将抛出一个异常,并且<code>抓</code>块将捕获它并报告错误。</p>
              <p>其次,请注意绑定参数如何在MySQLI示例中定位。占位符没有问号,而不是问号。这可能涉及一点额外的打字,但它有助于避免字段的数量或顺序变化的常见错误。使用命名参数,您无法在订单中获取您的参数,因为订单无关紧要。如果您喜欢位置参数而不是命名的参数,则PDO仍然支持它们。</p>
              <h3>这一点</h3>
              <p>当您查看这些示例的进展时,它似乎可能会在您可以将SQL汇集在字符串中并完成时将SQL代码与命名占位符一起创建SQL代码。</p>
              <p>不是。</p>
              <p>这些实施例中的每一个是对其之前的一个改进。这些技术是为了解决问题而创建的,而不仅仅是使程序员的生活更加困难。以下它们可以减少程序崩溃和故障,并帮助消除安全漏洞。这不仅仅是前端的额外努力吗?</p>
              <p></p>
              <p><em><a href="http://www.shutterstock.com/pic-148746329.html" target="_blank">背景图片</a>礼貌的<a href="http://www.shutterstock.com" target="_blank">shutterstock.com.</a>。</em></p>
             </div>
             <div class="tags">
              <i class="fa fa-tags"></i>
              <a href="//www.virtual-borneo.com/tag/database/" rel="tag">数据库</a>那<a href="//www.virtual-borneo.com/tag/php/" rel="tag">PHP.</a>那<a href="//www.virtual-borneo.com/tag/programming/" rel="tag">编程</a>那<a href="//www.virtual-borneo.com/tag/software-development/" rel="tag">软件开发</a>
             </div>
             <div class="author-box">
              <div class="author-meta">
               <img class="avatar avatar-100 photo" width="64" height="64" src="//www.virtual-borneo.com/wp-content/uploads/andy-lester-1.jpg">
               <p>Andy Lester从事开源工作已经20年了,为Perl贡献了许多模块<a href="http://search.cpan.org/~petdance/">CPAN.</a>以及在全国各地的开源会议和用户团体上发言。他是这个搜索工具的作者<a href="http://beyondgrep.com">ACK.</a>和他的书<em><a href="http://pragprog.com/book/algh/land-the-tech-job-you-love">土地你喜欢的技术工作</a></em>由务实书架发布。查看帖子<a href="//www.virtual-borneo.com/author/andylester/" title="安迪莱斯特" rel="author">安迪莱斯特</a>。</p>
               <div class="author-links">
                <a href="http://www.twitter.com/petdance"><i class="fa fa-twitter-square"></i></a>
                <a href="http://www.github.com/petdance"><i class="fa fa-github-square"></i></a>
               </div>
              </div>
             </div>
             <div class="legal-disendorsement">
              <p>在此博客上表达的观点是作者的观点,不一定反映新遗物的观点。作者提供亚博直播平台的任何解决方案是新遗物所提供的环境特定的,不是商业解决方案或支持的一部分。请在Explorer的集线器(讨论.newrelic.com)上以与此博客文章相关的问题和支持一起加入我们。此博客可能包含第三方网站上内容的链接。通过提供此类链接,新的遗物不会采用,保证,批准或支持此类站点上提供的信息,视图或产品。亚博最新版直播</p>
             </div>
             <p class="write-for-us">对新遗物博客的写作有兴趣吗?亚搏体育登入网<a href="mailto:blog@newrelic.com?subject=Guest post submission request&body=Please provide a description of what you'd like to write about for New Relic's blog:">给我们一个推介</a>!!</p>
             <div id="related-posts">
              <h3>相关文章</h3>
             </div>
            </article>
           </div>
          </div>
         </div>
        </div>
       </main>
      </section>
     </div>
     <!-- #main -->
     <!-- #primary -->
    </div>
   </div>
   <!-- /.main-wrap -->
   <footer id="footer-top">
    <div class="section">
     <div class="container">
      <div class="footer-columns">
       <div class="column">
        <h4>公司</h4>
        <ul class="list-unstyled">
         <li><a href="https://newrelic.com/about/culture">事业和文化</a></li>
         <li><a href="https://newrelic.com/solutions/partners">合作伙伴计划</a></li>
         <li><a href="https://ir.newrelic.com/">投资者关系</a></li>
         <li><a href="https://newrelic.org">newrelic.org.</a></li>
         <li><a href="https://newrelic.com/procurement/suppliers">供应商门户</a></li>
        </ul>
       </div>
       <div class="column">
        <h4>连接</h4>
        <ul class="list-unstyled">
         <li><a href="https://newrelic.com/about/contact-us">联系我们</a></li>
         <li><a href="https://newrelic.com/request-demo">请求演示</a></li>
         <li><a href="https://newrelic.com/community/events">活动</a></li>
        </ul>
       </div>
       <div class="column">
        <h4>国际的</h4>
        <ul class="list-unstyled">
         <li><a href="https://www.newrelic.co.jp">newrelic.co.jp(日语)</a></li>
         <li><a href="https://www.newrelic.fr/">Newrelic.fr(法语)</a></li>
         <li><a href="https://www.newrelic.de/">newrelic.de(德国)</a></li>
        </ul>
       </div>
      </div>
      <div class="social-icons">
       <ul class="list-unstyled">
        <li><a href="http://www.facebook.com/NewRelic" title="" target="_blank">
          <svg viewbox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
           <path d="M1376 128q119 0 203.5 84.5t84.5 203.5v960q0 119-84.5 203.5t-203.5 84.5h-188v-595h199l30-232h-229v-148q0-56 23.5-84t91.5-28l122-1v-207q-63-9-178-9-136 0-217.5 80t-81.5 226v171h-200v232h200v595h-532q-119 0-203.5-84.5t-84.5-203.5v-960q0-119 84.5-203.5t203.5-84.5h960z"></path>
          </svg></a></li>
        <li><a href="http://www.twitter.com/NewRelic" title="" target="_blank">
          <svg viewbox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
           <path d="M1408 610q-56 25-121 34 68-40 93-117-65 38-134 51-61-66-153-66-87 0-148.5 61.5t-61.5 148.5q0 29 5 48-129-7-242-65t-192-155q-29 50-29 106 0 114 91 175-47-1-100-26v2q0 75 50 133.5t123 72.5q-29 8-51 8-13 0-39-4 21 63 74.5 104t121.5 42q-116 90-261 90-26 0-50-3 148 94 322 94 112 0 210-35.5t168-95 120.5-137 75-162 24.5-168.5q0-18-1-27 63-45 105-109zm256-194v960q0 119-84.5 203.5t-203.5 84.5h-960q-119 0-203.5-84.5t-84.5-203.5v-960q0-119 84.5-203.5t203.5-84.5h960q119 0 203.5 84.5t84.5 203.5z"></path>
          </svg></a></li>
        <li><a href="https://www.linkedin.com/company/new-relic-inc-" title="" target="_blank">
          <svg viewbox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
           <path d="M365 1414h231v-694h-231v694zm246-908q-1-52-36-86t-93-34-94.5 34-36.5 86q0 51 35.5 85.5t92.5 34.5h1q59 0 95-34.5t36-85.5zm585 908h231v-398q0-154-73-233t-193-79q-136 0-209 117h2v-101h-231q3 66 0 694h231v-388q0-38 7-56 15-35 45-59.5t74-24.5q116 0 116 157v371zm468-998v960q0 119-84.5 203.5t-203.5 84.5h-960q-119 0-203.5-84.5t-84.5-203.5v-960q0-119 84.5-203.5t203.5-84.5h960q119 0 203.5 84.5t84.5 203.5z"></path>
          </svg></a></li>
        <li><a href="https://www.youtube.com/user/NewRelicInc/featured" title="" target="_blank">
          <svg viewbox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
           <path d="M1047 1303v-157q0-50-29-50-17 0-33 16v224q16 16 33 16 29 0 29-49zm184-122h66v-34q0-51-33-51t-33 51v34zm-571-266v70h-80v423h-74v-423h-78v-70h232zm201 126v367h-67v-40q-39 45-76 45-33 0-42-28-6-17-6-54v-290h66v270q0 24 1 26 1 15 15 15 20 0 42-31v-280h67zm252 111v146q0 52-7 73-12 42-53 42-35 0-68-41v36h-67v-493h67v161q32-40 68-40 41 0 53 42 7 21 7 74zm251 129v9q0 29-2 43-3 22-15 40-27 40-80 40-52 0-81-38-21-27-21-86v-129q0-59 20-86 29-38 80-38t78 38q21 29 21 86v76h-133v65q0 51 34 51 24 0 30-26 0-1 .5-7t.5-16.5v-21.5h68zm-451-824v156q0 51-32 51t-32-51v-156q0-52 32-52t32 52zm533 713q0-177-19-260-10-44-43-73.5t-76-34.5q-136-15-412-15-275 0-411 15-44 5-76.5 34.5t-42.5 73.5q-20 87-20 260 0 176 20 260 10 43 42.5 73t75.5 35q137 15 412 15t412-15q43-5 75.5-35t42.5-73q20-84 20-260zm-755-651l90-296h-75l-51 195-53-195h-78q7 23 23 69l24 69q35 103 46 158v201h74v-201zm289 81v-130q0-58-21-87-29-38-78-38-51 0-78 38-21 29-21 87v130q0 58 21 87 27 38 78 38 49 0 78-38 21-27 21-87zm181 120h67v-370h-67v283q-22 31-42 31-15 0-16-16-1-2-1-26v-272h-67v293q0 37 6 55 11 27 43 27 36 0 77-45v40zm503-304v960q0 119-84.5 203.5t-203.5 84.5h-960q-119 0-203.5-84.5t-84.5-203.5v-960q0-119 84.5-203.5t203.5-84.5h960q119 0 203.5 84.5t84.5 203.5z"></path>
          </svg></a></li>
        <li><a href="https://www.instagram.com/newrelic/" title="" target="_blank">
          <svg viewbox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
           <path d="M1152 896q0-106-75-181t-181-75-181 75-75 181 75 181 181 75 181-75 75-181zm138 0q0 164-115 279t-279 115-279-115-115-279 115-279 279-115 279 115 115 279zm108-410q0 38-27 65t-65 27-65-27-27-65 27-65 65-27 65 27 27 65zm-502-220q-7 0-76.5-.5t-105.5 0-96.5 3-103 10-71.5 18.5q-50 20-88 58t-58 88q-11 29-18.5 71.5t-10 103-3 96.5 0 105.5.5 76.5-.5 76.5 0 105.5 3 96.5 10 103 18.5 71.5q20 50 58 88t88 58q29 11 71.5 18.5t103 10 96.5 3 105.5 0 76.5-.5 76.5.5 105.5 0 96.5-3 103-10 71.5-18.5q50-20 88-58t58-88q11-29 18.5-71.5t10-103 3-96.5 0-105.5-.5-76.5.5-76.5 0-105.5-3-96.5-10-103-18.5-71.5q-20-50-58-88t-88-58q-29-11-71.5-18.5t-103-10-96.5-3-105.5 0-76.5.5zm768 630q0 229-5 317-10 208-124 322t-322 124q-88 5-317 5t-317-5q-208-10-322-124t-124-322q-5-88-5-317t5-317q10-208 124-322t322-124q88-5 317-5t317 5q208 10 322 124t124 322q5 88 5 317z"></path>
          </svg></a></li>
       </ul>
      </div>
      <div class="links">
       <span><a href="https://newrelic.com/termsandconditions/terms">服务条款</a></span>
       <span><a href="https://newrelic.com/termsandconditions/dmca">DMCA政策</a></span>
       <span><a href="https://newrelic.com/termsandconditions/privacy">隐私政策</a></span>
       <span><a href="https://newrelic.com/termsandconditions/cookie-policy">Cookie政策</a></span>
       <span><a href="https://newrelic.com/termsandconditions/uk-slavery-act">英国2015年奴隶制法案</a></span>
      </div>
      <p class="copy"><span>©2008-21 New Relic,Inc。保留所有权利</span></p>
     </div>
    </div>
   </footer>
  </div>
 </body>
</html>