PHP学习(3)——数据的存储与检索
要点目录:
1.保存数据的方法
存储数据有两种基本方法:保存到普通文件,或者保存到数据库中。当具有大量订单时,应该使用一个数据库管理系统。
2.订单添加收货地址
本篇将使用上一篇所介绍的订单的改进版本。
Html代码如下:
<html>
<head>
<title>Bob's Auto Parts</title>
</head>
<body>
<h1>Bob's Auto Parts</h1>
<h2>Order Form</h2> <form action="processorder.php" method="post">
<table border="0">
<tr bgcolor="#cccccc">
<td width="150">Item</td>
<td width="15">Quantity</td>
</tr>
<tr>
<td>Tires</td>
<td align="left"><input type="text" name="tireqty" size="3" maxlength="3"/></td>
</tr>
<tr>
<td>Oil</td>
<td align="left"><input type="text" name="oilqty" size="3" maxlength="3"/></td>
</tr>
<tr>
<td>Spark Plugs</td>
<td align="left"><input type="text" name="sparkqty" size="3" maxlength="3"/></td>
</tr>
<tr>
<td>Shipping Address</td>
<td align="center"><input type="text" name="address" size="40" maxlength="40"/></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="Submit Order"/></td>
</tr>
</table>
</form> </body>
</html>
3.打开文件
fopen()函数可以打开一个文件。
$fp = fopen(“$DOCUMENT_ROOT/orders.txt”,’w’);
由于我们为表单变量定义了一个简短名称,我们需要在脚本的开始处加上如下代码:
$DOCUMENT_ROOT = $_SERVER[‘DOCUMENT_ROOT’];
可以通过如下3种方式得到文档根目录:
$_SERVER[‘DOCUMENT_ROOT’] $DOCUMENT_ROOT $HTTP_SERVER_VARS[‘DOCUMENT_ROOT’]
fopen()有四个参数,其中第一个参数是路径。
第二个参数是文件模式。
第三个参数可选,如果要在include_path中搜索一个文件,就可以使用它。
第四个参数也可选,fopen()函数允许文件名称以协议名称开始并且在一个远程的位置打开文件。
也可以使用fopen()函数通过FTP、HTTP或其他协议来打开文件。
注意,URL中的域名不区分大小写,但是路径和文件名可能会区分大小写。
4.打开文件时可能遇到的问题
设置了不正确的访问权限可能是造成打开文件时出现错误的常见原因。
任何人都可以写的目录和文件时非常危险的,后面的文章会详细介绍安全问题。
If语句可以用来测试变量$fp,查看fopen()函数是否返回了一个有效的文件指针。
@$fp = fopen("$DOCUMENT_ROOT/orders.txt", 'ab'); if (!$fp) { echo "<p><strong> Your order could not be processed at this time. Please try again later.</strong></p></body></html>"; exit; }
用自己的错误信息替代PHP的错误信息可以使用户觉得更加友好。
5.写文件
可以使用fwrite()写文件。
int fwrite(resource handle, string string [, int length])
第一个参数是文件。第二个参数是数据。第三个参数可选,是最大字符数。可以通过PHP的内置strlen()函数获得字符串的长度:
fwrite($fp, $outputstring, strlen($outputstring));
定义保存的数据格式:
$outputstring = $date."\t".$tireqty." tires \t".$oilqty." oil\t" .$sparkqty." spark plugs\t\$".$totalamount ."\t". $address."\n";
选择每行记录一个订单这种格式是因为这样可以使用换行字符作为简单的记录间隔符。
处理了一些订单后,该文件的内容将类似如下:
08:00, 9th August 2016 1 tires 1 oil 1 spark plugs $114.00 s
08:51, 9th August 2016 1 tires 1 oil 1 spark plugs $114.00 s
08:51, 9th August 2016 112 tires 121 oil 111 spark plugs $12 854.00 sasdf
6.关闭文件
按照如下方式调用fclose()函数即可:
fclose($fp)
订单处理脚本processorder.php源码:
<?php
// create short variable names
$tireqty = $_POST['tireqty'];
$oilqty = $_POST['oilqty'];
$sparkqty = $_POST['sparkqty'];
$address = $_POST['address'];
$DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
$date = date('H:i, jS F Y');
?>
<html>
<head>
<title>Bob's Auto Parts - Order Results</title>
</head>
<body>
<h1>Bob's Auto Parts</h1>
<h2>Order Results</h2>
<?php echo "<p>Order processed at ".date('H:i, jS F Y')."</p>"; echo "<p>Your order is as follows: </p>"; $totalqty = 0;
$totalqty = $tireqty + $oilqty + $sparkqty;
echo "Items ordered: ".$totalqty."<br />"; if ($totalqty == 0) { echo "You did not order anything on the previous page!<br />"; } else { if ($tireqty > 0) {
echo $tireqty." tires<br />";
} if ($oilqty > 0) {
echo $oilqty." bottles of oil<br />";
} if ($sparkqty > 0) {
echo $sparkqty." spark plugs<br />";
}
} $totalamount = 0.00; define('TIREPRICE', 100);
define('OILPRICE', 10);
define('SPARKPRICE', 4); $totalamount = $tireqty * TIREPRICE
+ $oilqty * OILPRICE
+ $sparkqty * SPARKPRICE; $totalamount=number_format($totalamount, 2, '.', ' ');//通过千位分组来格式化数字 echo "<p>Total of order is $".$totalamount."</p>";
echo "<p>Address to ship to is ".$address."</p>"; $outputstring = $date."\t".$tireqty." tires \t".$oilqty." oil\t"
.$sparkqty." spark plugs\t\$".$totalamount
."\t". $address."\n"; // open file for appending
@ $fp = fopen("$DOCUMENT_ROOT/orders.txt", 'ab'); flock($fp, LOCK_EX); //写操作锁定 if (!$fp) {
echo "<p><strong> Your order could not be processed at this time.
Please try again later.</strong></p></body></html>";
exit;
} fwrite($fp, $outputstring, strlen($outputstring));
flock($fp, LOCK_UN); //释放锁定
fclose($fp); echo "<p>Order written.</p>";
?>
</body>
</html>
7.读文件
用来查看订单文件的员工界面:
<?php
//create short variable name
$DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
?>
<html>
<head>
<title>Bob's Auto Parts - Customer Orders</title>
</head>
<body>
<h1>Bob's Auto Parts</h1>
<h2>Customer Orders</h2>
<?php @$fp = fopen("$DOCUMENT_ROOT/orders.txt", 'rb'); //只读模式 flock($fp, LOCK_SH); // lock file for reading if (!$fp) {
echo "<p><strong>No orders pending.
Please try again later.</strong></p>";
exit;
} while (!feof($fp)) {
$order= fgets($fp, 999);
echo $order."<br />";
} echo "Final position of the file pointer is ".(ftell($fp)); //指针当前位置
echo "<br />";
rewind($fp);
echo "After rewind, the position is ".(ftell($fp)); //指针复位
echo "<br />"; flock($fp, LOCK_UN); // release read lock fclose($fp); ?>
</body>
</html>
这段脚本是按照前面所介绍的步骤进行的:打开文件、读文件、关闭文件。下面进行详细说明。
7.1 知道何时读完文件:feof()
使用feof()函数作为文件结束的测试条件:
while(!feof($fp))
函数feof()的唯一参数是文件指针。如果该文件指针指向了文件末尾,它将返回true。feof表示File End Of File。
7.2 每次读取一行数据:fgets()、fgetss()和fgetcsv()
这个例子中使用了fgets()函数来读取文件内容:
$order = fgets($fp, 999);
这个函数可以从文件中每次读取一行内容。这样,它将不断地读入数据,直至读到一个换行字符(\n)、或者文件结束符EOF,或者是从文件中读取了998B。可以读取的最大长度为指定的长度减去1B。
出于操作安全的考虑可以使用fgetss()函数:
string fgetss(resource fp, int length, string [allowable_tags]);
如果希望重新构建订单中的变量,而不是将整个订单作为一行文本,使用fgetcsv()函数可以很容易实现。
array fgetcsv( resource fp, int length [, string delimiter[, string enclosure]])
7.3 读取整个文件:readfile()、fpassthru()和file()
有四种方式可以一次读取整个文件:
1)readfile()
readfile(“$DOCUMENT_ROOT/orders.txt”);
调用readfile()函数将打开这个文件,并且将文件内容输出到标准输出中,然后再关闭这个文件。readfile()的函数原型如下:
int readfile(string filename, [int use_include_path [, resource context]]);
第二个可选参数指定了PHP是否应该在include_path中查找文件。
2)fpassthru()
要使用这个函数,必须先使用fopen()打开文件。然后将文件指针作为参数传递给fpassthru()。
可以使用如下代码替代前面的脚本:
$fp = fopen(“$DOCUMENT_ROOT/orders.txt”,’rb’); fpassthru($fp);
3)file()
除了可以将文件内容会显到标准输出外,它和readfile()是一样的。
4)file_get_contents()
与readfile()基本相同。不同之处是该函数将以字符串的形式返回文件内容,而不是将文件内容回显到浏览器中。
7.4 读取一个字符:fgetc()
while(!feof($fp)){ $char = fgetc($fp); if(!feof($fp)){ echo ($char == “\n”?”<br />”:$char); } }
这段代码使用fgetc()函数从文件中一次读取一个字符,并且将该字符保存在$char中,直到文件结束。然后再用HTML的换行符(<br />)替换文本中的行结束符(\n)。
使用fgetc()函数的一个缺点就是它返回文件结束符EOF,而fgets()则不会。读取出字符后还需要判断feof(),因为我们并不希望将文件结束符EOF回显到浏览器中。
7.5 读取任意长度:fread()
String fread(resource fp, int length);
8.使用其他有用的文件函数
8.1 查看文件是否存在:file_exists()
if(file_exists(“$DOCUMENT_ROOT/orders.txt”)){ echo ‘There are orders waiting to be processed.’; }
else{ echo ‘There are currently no orders.’; }
8.2 确定文件大小:filesize()
echo filesize(“$DOCUMENT_ROOT/orders.txt”);
8.3 删除一个文件:unlink()
unlink(“$DOCUMENT_ROOT/orders.txt”);
通常,如果对该文件的访问权限不够或者该文件不存在,该函数将返回false。
8.4 在文件中定位:rewind()、fseek()和ftell()
rewind()函数可以将文件指针复位到文件的开始。
ftell()函数可以以字节为单位报告文件指针当前在文件中的位置。
fseek()函数将文件指针指向文件的某个位置:
int fseek( resource fp, int offset[, int whence])
9.文件锁定
假设两个客户试图同时订购同一件商品,可以使用文件锁定的方法。当一个文件被打开并且在进行读写操作之前,应该调用这个函数。
bool flock(resource fp, int operation [, int & wouldblock])
还必须将一个指向被打开文件的指针和一个表示所需锁定类型的常数作为参数传递给这个函数。如果文件锁定成功,其返回值为true,否则为false。如果获得文件锁将导致当前的进程被阻塞,可选的第三个参数将包含值true。
operation参数的可能值:
LOCK_SH:读操作锁定
LOCK_EX:写操作锁定
LOCK_UN:释放已有的锁定
LOCK_NB:防止在请求加锁时发生阻塞
flock()函数无法在NFS或其他网络文件系统中使用。在某些操作系统中,它是在进程级别上实现的,如果你在多线程服务器API中使用,该函数也无法正确使用。
如果有两个脚本同时申请对一个文件加锁,就需要使用数据库管理系统(DBMS)。
10.更好的方式:数据库管理系统
相比使用普通文件的优势:
1)更快的数据访问
2)易查找并检索满足特定条件的数据集合
3)具有内置的处理并发访问的机制
4)可以随机访问数据
5)具有内置的权限系统
后面的文章会详细介绍数据库。
整理自《PHP与MySQL Web开发》
PHP学习(3)——数据的存储与检索的更多相关文章
- 从零开始PHP攻略(3)——数据的存储与检索
要点目录: I.保存数据 II.打开文件 III.创建并写入文件 IV.关闭文件 V.读文件 VI.给文件加锁 VII.删除文件 VIII.其他有用的文件操作函数 IX.数据库管理系统 1.保存数 ...
- PHP对文件数据的存储和检索
@(主要是对文件的操作) 文件处理:php操作文件主要是写入和读取这两种.执行的步骤都是一样的. 1.打开这个文件.如果打不开就先创建它.2.将数据写入这个文件,或者将数据读出这个文件.3.关闭文件. ...
- 【Cocos2d-X开发学习笔记】第29期:游戏中数据的存储(上)
本系列学习教程使用的是cocos2d-x-2.1.4(最新版为3.0alpha0-pre) ,PC开发环境Windows7,C++开发环境VS2010 一般游戏中都需要记录玩家数据,便于玩家下次登录时 ...
- 【Cocos2d-X开发学习笔记】第30期:游戏中数据的存储(下)
本系列学习教程使用的是cocos2d-x-2.1.4(最新版为3.0alpha0-pre) ,PC开发环境Windows7,C++开发环境VS2010 一.对数据进行编解码 在上一期中,我们使用了CC ...
- iOS学习笔记--数据存储
iOS应用数据存储的常用方式 XML属性列表(plist)归档 Preference(偏好设置) NSKeyedArchiver归档(NSCoding) SQLite3 Core Data 1. XM ...
- Unity3D学习(二):使用JSON进行对象数据的存储读取
前言 前段时间完成了自己的小游戏Konster的制作,今天重新又看了下代码.原先对关卡解锁数据的存储时用了Unity自带的PlayerPref(字典式存储数据). 读取关卡数据的代码: void Aw ...
- 大数据技术之_08_Hive学习_04_压缩和存储(Hive高级)+ 企业级调优(Hive优化)
第8章 压缩和存储(Hive高级)8.1 Hadoop源码编译支持Snappy压缩8.1.1 资源准备8.1.2 jar包安装8.1.3 编译源码8.2 Hadoop压缩配置8.2.1 MR支持的压缩 ...
- HTML5深入学习之数据存储
概述 本来,数据存储都是由 cookie 完成的,但是 cookie 不适合大量数据的存储,cookie 速度慢且效率低. 现在,HMLT5提供了两种在客户端存储数据的办法: localStorage ...
- 云计算和大数据时代网络技术揭秘(八)数据中心存储FCoE
数据中心存储演化——FCoE 数据中心三大基础:主机 网络 存储 在云计算推动下,存储基础架构在发生演变 传统存储结构DAS.SAN在发展中遇到了布线复杂.能耗增多的缺点(原生性),需要对架构做根 ...
随机推荐
- Qt 程序自动重启的实现
正常退出调用exit() 或quit()就行,想要自已重启可按下面代码: void XXX:onRestart() { //类中调用 qApp->exit(); } 主main函数中处理 int ...
- redis常见问题(转)
常见问题:1.为什么使用redis(一)性能我们在碰到需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存.这样,后面的请求就去缓存中读取,使得请求能够迅速响应.(二)并发在大并 ...
- python不换行输出
python默认的print是换行输出的.要想实现不换行输出,方法如下: python 2.X版本: print('要在print后面加个逗号-> , '), python 3.X版本: pri ...
- 括号序列的dp问题模型
括号序列的dp问题模型 Codeforces314E ◦给定一个长度为n的仅包含左括号和问号的字符串,将问号变成左括号或 右括号使得该括号序列合法,求方案总数. ◦例如(())与()()都是合法的括号 ...
- tensorflow实现siamese网络 (附代码)
转载自:https://blog.csdn.net/qq1483661204/article/details/79039702 Learning a Similarity Metric Discrim ...
- jmeter从文件中读取参数,并实现循环
1. 通过BeanShell Sampler获取csv的行数 import java.io.BufferedReader;import java.io.FileReader;BufferedReade ...
- MAC ADDRESS
可以使用手机Wifi或蓝牙的MAC地址作为设备标识,但是并不推荐这么做,原因有以下两点:硬件限制:并不是所有的设备都有Wifi和蓝牙硬件,硬件不存在自然也就得不到这一信息.获取的限制:如果Wifi没有 ...
- 20.包含min函数的栈 Java
题目描述 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1)). 思路 借助辅助栈实现: 压栈时:若辅助栈为空,则将节点压入辅助栈.否则,当当前节点小于 ...
- JVM----Class类文件结构
JVM平台无关性 Java具有平台无关性,也就是任何操作系统都能运行Java代码.之所以能实现这一点,是因为Java运行在虚拟机之上,不同的操作系统都拥有各自的Java虚拟机,因此Java能实现“一次 ...
- IPv4 地址分类-for what
怎么分的:IPV4 地址分类 A B C D E 分来做什么:IP地址为什要分类?就是a类,b类,c类...? - wuxinliulei的回答 - 知乎