3. PHP的基础知识
3.1. 第一个示例
下面是一个展示 PHP 基本特性的程序。
3.1.1. 该程序(exemple_01)
<?php
// 这是一条注释
// 未声明即使用的变量
$nom = "dupont";
// 屏幕显示
print "nom=$nom\n";
// 包含不同类型元素的数组
$tableau = array("un", "deux", 3, 4);
// 其元素个数
$n = count($tableau);
// 一个循环
for ($i = 0; $i < $n; $i++)
print "tableau[$i]=$tableau[$i]\n";
// 使用数组内容初始化两个变量
list($chaine1, $chaine2) = array("chaine1", "chaine2");
// 将两个字符串拼接
$chaine3 = $chaine1 . $chaine2;
// 显示结果
print "[$chaine1,$chaine2,$chaine3]\n";
// 使用函数
affiche($chaine1);
// 变量的类型可以确定
afficheType($n);
afficheType($chaine1);
afficheType($tableau);
// 变量的类型在运行时可能会改变
$n = "a changé";
afficheType($n);
// 函数可以返回结果
$res1 = f1(4);
print "res1=$res1\n";
// 函数可以返回一个值数组
list($res1, $res2, $res3) = f2();
print "(res1,res2,res3)=[$res1,$res2,$res3]\n";
// 本可以将这些值存入数组中
$t = f2();
for ($i = 0; $i < count($t); $i++)
print "t[$i]=$t[$i]\n";
// 测试
for ($i = 0; $i < count($t); $i++)
//仅显示频道
if (getType($t[$i]) == "string")
print "t[$i]=$t[$i]\n";
// 其他测试
for ($i = 0; $i < count($t); $i++){
// 仅显示大于10的整数
if (getType($t[$i]) == "integer" and $t[$i] > 10)
print "t[$i]=$t[$i]\n";
}
// 一个 while 循环
$t = array(8, 5, 0, -2, 3, 4);
$i = 0;
$somme = 0;
while ($i < count($t) and $t[$i] > 0) {
print "t[$i]=$t[$i]\n";
$somme+=$t[$i]; //$somme=$somme+$t[$i]
$i++; //$i=$i+1
}
print "somme=$somme\n";
// 程序结束
exit;
//----------------------------------
function affiche($chaine) {
// 显示 $chaine
print "chaine=$chaine\n";
}
//----------------------------------
function afficheType($variable) {
// 显示 $variable 的类型
print "type[$variable]=" . getType($variable) . "\n";
}
//----------------------------------
function f1($param) {
// 将 10 加到 $param
return $param + 10;
}
//----------------------------------
function f2() {
// 返回 3 个值
return array("un", 0, 100);
}
?>
结果:
注释
- 第 5 行:在 PHP 中,未声明变量的类型。这些变量具有动态类型,其类型可能会随时间变化
- $nom 表示标识符 nom 的变量
- 第8行:要向屏幕输出内容,可以使用指令 print 或指令 echo
- 第 11 行:关键字 array 用于定义数组。 变量 $nom[$i] 表示数组 $tableau 中的元素 $i。
- 第 14 行:函数 count($tableau) 返回数组 $tableau 的元素个数
- 第 18 行:字符串用双引号 " 或单引号 ' 括起。在双引号内,变量 $variable 会被求值,但在单引号内则不会。
- 第 21 行:函数 list 可将变量集合到列表中,并通过单次赋值操作为其赋值。此处 $chaine1="chaine1" 且 $chaine2="chaine2"。
- 第 24 行:运算符 . 是字符串连接运算符。
- 第 88 行:关键字 function 定义了一个函数。函数是否返回值由语句 return 决定。调用代码可以忽略或获取函数的结果。函数可以在代码中的任意位置定义。
- 第 90 行:预定义函数 getType($variable) 返回一个字符串,该字符串表示 $variable 的类型。该类型可能会随时间变化。
- 第 79 行:预定义函数 exit 终止脚本。
3.2. 变量的作用域
3.2.1. 程序 1 (exemple_02)
<?php
// 变量的作用域
function f1() {
// 使用全局变量 $i
$i = &$GLOBALS["i"];
$i++;
$j = 10;
print "f1[i,j]=[$i,$j]\n";
}
function f2() {
// 使用全局变量 $i
$i = &$GLOBALS["i"];
$i++;
$j = 20;
print "f2[i,j]=[$i,$j]\n";
}
function f3() {
// 使用局部变量 $i
$i = 4;
$j = 30;
print "f3[i,j]=[$i,$j]\n";
}
// 测试
$i = 0;
$j = 0; // 函数 f 通过数组 $GLOBALS 知晓这两个变量
f1();
f2();
f3();
print "test[i,j]=[$i,$j]\n";
?>
结果:
注释
- 第 29-30 行:定义了主程序中的两个变量 $i 和 $j。这些变量在函数内部不可见。 因此,第 9 行中,函数 f1 中的变量 $j 是函数 f1 的局部变量,与主程序中的变量 $j 不同。 一个函数可以通过名为 $GLOBALS 的全局变量表访问主程序中的变量 $variable。 第 7 行,$GLOBALS["i"] 表示主程序的全局变量 $i。如果我们写
,则局部变量 $i 将被赋值为全局变量 $i 的值。这里有两个不同的变量,修改局部变量 $i 不会改变全局变量 $i。该表示法
导致局部变量 $i 与全局变量 $i 具有相同的内存地址。因此,操作局部变量 $i 实际上等同于操作全局变量 $i。
3.2.2. 程序 2 (exemple_03)
<?php
// 变量的作用域在代码块中是全局的
$i = 0; {
$i = 4;
$i++;
}
print "i=$i\n";
?>
结果:
注释
在某些语言中,大括号内定义的变量作用域仅限于大括号内部:在大括号外部无法访问该变量。 上述结果表明,在 PHP 中并非如此。第 5 行在大括号内定义的变量 $i 与第 4 行和第 8 行在大括号外使用的变量是同一个。
3.3. 数组
3.3.1. 经典的一维数组(exemple_04)
<?php
// 经典数组
// 初始化
$tab1 = array(0, 1, 2, 3, 4, 5);
// 遍历 - 1
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++)
print "tab1[$i]=$tab1[$i]\n";
// 遍历 - 2
print "tab1 a " . count($tab1) . " éléments\n";
reset($tab1);
while (list($clé, $valeur) = each($tab1))
print "tab1[$clé]=$valeur\n";
// 添加元素
$tab1[] = $i++;
$tab1[] = $i++;
// 遍历 - 3
print "tab1 a " . count($tab1) . " éléments\n";
$i = 0;
foreach ($tab1 as $élément) {
print "tab1[$i]=$élément\n";
$i++;
}
// 删除最后一个元素
array_pop($tab1);
// 遍历 - 4
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++)
print "tab1[$i]=$tab1[$i]\n";
// 删除第一个元素
array_shift($tab1);
// 遍历 - 5
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++)
print "tab1[$i]=$tab1[$i]\n";
// 在数组末尾插入
array_push($tab1, -2);
// 遍历 - 6
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++)
print "tab1[$i]=$tab1[$i]\n";
// 在数组开头插入
array_unshift($tab1, -1);
// 遍历 - 7
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++)
print "tab1[$i]=$tab1[$i]\n";
?>
结果:
注释
上述程序演示了对数组值的操作。在 PHP 中,数组有两种表示法:
表 1 称为数组,表 2 称为字典,其中元素以键 => 值的形式表示。 $contraires["beau"] 表示与键“beautiful”关联的值。因此,此处的值为字符串“ugly”。数组 1 只是字典的一种变体,也可以表示为:
因此,$tableau[2] 表示“trois”。 归根结底,所有数据结构本质上都是字典。对于包含 n 个元素的经典数组,其键是 [0,n-1] 区间内的整数。
- 第15行:each($tableau)函数用于遍历字典。每次调用时,它都会返回该字典中的一对(键,值)。
- 第 14 行:reset($dictionnaire) 函数将 each 函数定位到字典中的第一个 (键,值) 对。
- 第 15 行:当函数 each 在字典结尾返回一个空元组时,循环 while 终止。
- 第 19 行:$tableau[]=value 语法将元素 valeur 作为 $tableau 的最后一个元素添加进去。
- 第 25 行:使用 foreach 遍历数组。该语法元素支持通过两种语法遍历字典(即数组):
第一种语法在每次迭代时返回一个元组 (clé,valeur),而第二种语法仅返回字典中的 valeur 元素。
- 第 31 行:函数 array_pop($tableau) 删除了 $tableau 的最后一个元素
- 第 39 行:函数 array_shift($tableau) 删除 $tableau 的第一个元素
- 第 47 行:函数 array_push($tableau,value) 将 valeur 作为最后一个元素添加到 $tableau 中
- 第 39 行:函数 array_unshift($tableau,value) 将 valeur 作为 $tableau 的第一个元素添加
3.3.2. 字典 (exemple_05)
<?php
// 词典
$conjoints = array("Pierre" => "Gisèle", "Paul" => "Virginie", "Jacques" => "Lucette", "Jean" => "");
// 遍历 - 1
print "Nombre d'éléments du dictionnaire : " . count($conjoints) . "\n";
reset($conjoints);
while (list($clé, $valeur) = each($conjoints))
print "conjoints[$clé]=$valeur\n";
// 按键值对排序字典
ksort($conjoints);
// 遍历 - 2
reset($conjoints);
while (list($clé, $valeur) = each($conjoints))
print "conjoints[$clé]=$valeur\n";
// 字典键列表
$clés = array_keys($conjoints);
for ($i = 0; $i < count($clés); $i++)
print "clés[$i]=$clés[$i]\n";
// 字典值列表
$valeurs = array_values($conjoints);
for ($i = 0; $i < count($valeurs); $i++)
print "valeurs[$i]=$valeurs[$i]\n";
// 查找键
existe($conjoints, "Jacques");
existe($conjoints, "Lucette");
existe($conjoints, "Jean");
// 删除键值对
unset($conjoints["Jean"]);
print "Nombre d'éléments du dictionnaire : " . count($conjoints) . "\n";
foreach ($conjoints as $clé => $valeur) {
print "conjoints[$clé]=$valeur\n";
}
// 结束
exit;
function existe($conjoints, $mari) {
// 检查键 $mari 是否存在于字典 $conjoints 中
if (isset($conjoints[$mari]))
print "La clé [$mari] existe associée à la valeur [$conjoints[$mari]]\n";
else
print "La clé [$mari] n'existe pas\n";
}
?>
结果:
注释
上述代码将之前针对简单数组的内容应用到了字典上。我们仅对新增内容进行说明:
- 第13行:ksort(键排序)函数可按键的自然顺序对字典进行排序。
- 第21行:函数 array_keys($dictionnaire) 将字典的键列表以数组形式返回
- 第 26 行:函数 array_values($dictionnaire) 将字典的值列表以表格形式输出
- 第47行:函数isset($variable) 返回 true,如果变量 $variable 已被定义;否则返回 false。
- 第 36 行:函数 unset($variable) 会删除变量 $variable。
3.3.3. 多维数组 (exemple_06)
<?php
// 经典多维数组
// 初始化
$multi = array(array(0, 1, 2), array(10, 11, 12, 13), array(20, 21, 22, 23, 24));
// 遍历
for ($i1 = 0; $i1 < count($multi); $i1++)
for ($i2 = 0; $i2 < count($multi[$i1]); $i2++)
print "multi[$i1][$i2]=" . $multi[$i1][$i2] . "\n";
// 多维字典
// 初始化
$multi = array("zéro" => array(0, 1, 2), "un" => array(10, 11, 12, 13), "deux" => array(20, 21, 22, 23, 24));
// 遍历
foreach ($multi as $clé => $valeur)
for ($i2 = 0; $i2 < count($valeur); $i2++)
print "multi[$clé][$i2]=" . $multi[$clé][$i2] . "\n";
?>
结果:
注释
- 第 5 行:数组 $multi 的元素本身也是数组
- 第12行:数组$multi被转换为一个字典(clé,valeur),其中每个valeur都是一个数组
3.3.4. 字符串与数组之间的关联(exemple_07)
<?php
// 字符串转数组
$chaine = "1:2:3:4";
$tab = explode(":", $chaine);
// 数组遍历
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++)
print "tab[$i]=$tab[$i]\n";
// 数组转字符串
$chaine2 = implode(":", $tab);
print "chaine2=$chaine2\n";
// 添加一个空字段
$chaine.=":";
print "chaîne=$chaine\n";
$tab = explode(":", $chaine);
// 遍历数组
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++)
print "tab[$i]=$tab[$i]\n"; // 现在有 5 个元素,最后一个为空
// 再次添加一个空字段
$chaine.=":";
print "chaîne=$chaine\n";
$tab = explode(":", $chaine);
// 遍历数组
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++)
print "tab[$i]=$tab[$i]\n"; // 现在共有 6 个元素,最后两个为空
?>
结果:
注释
- 第 5 行:函数 explode($séparateur,$chaine) 可提取由 $séparateur 分隔的 $chaine 字段。 因此,explode(":",$chaine) 可将 $chaine 中以字符串 ":" 分隔的元素以数组形式提取出来。
- 函数 implode($séparateur,$tableau) 执行与 explode 函数相反的操作。它返回一个字符串,该字符串由 $tableau 的元素组成,这些元素由 $séparateur 分隔。
3.4. 字符串
3.4.1. 符号 (exemple_08)
<?php
// 字符串表示法
$chaine1 = "un";
$chaine2 = 'un';
print "[$chaine1,$chaine2]\n";
?>
结果:
3.4.2. 比较 (exemple_09)
<?php
// 字符串比较测试
compare("abcd", "abcd");
compare("", "");
compare("1", "");
exit;
function compare($chaine1, $chaine2) {
// 比较字符串1和字符串2
if ($chaine1 == $chaine2)
print "[$chaine1] est égal à [$chaine2]\n";
else
print "[$chaine1] est différent de [$chaine2]\n";
}
?>
结果:
3.5. 正则表达式 (exemple_10)
<?php
// PHP 中的正则表达式
// 提取字符串中的各个字段
// 模式:由任意字符包围的一串数字
// 仅提取数字序列
$modèle = "/(\d+)/";
// 将字符串与模式进行比对
compare($modèle, "xyz1234abcd");
compare($modèle, "12 34");
compare($modèle, "abcd");
// 模式:由任意字符包围的一串数字
// 需要提取数字序列及其前后相邻的字段
$modèle = "/^(.*?)(\d+)(.*?)$/";
// 将字符串与模式进行匹配
compare($modèle, "xyz1234abcd");
compare($modèle, "12 34");
compare($modèle, "abcd");
// 模式:日期格式为 dd/mm/yy
$modèle = "/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/";
compare($modèle, "10/05/97");
compare($modèle, " 04/04/01 ");
compare($modèle, "5/1/01");
// 模式——一个十进制数
$modèle = "/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/";
compare($modèle, "187.8");
compare($modèle, "-0.6");
compare($modèle, "4");
compare($modèle, ".6");
compare($modèle, "4.");
compare($modèle, " + 4");
// 结束
exit;
// --------------------------------------------------------------------------
function compare($modèle, $chaîne) {
// 将字符串 $chaîne 与模板 $modèle 进行比较
// 将字符串与模板进行比对
$correspond = preg_match($modèle, $chaîne, $champs);
// 显示结果
print "\nRésultats($modèle,$chaîne)\n";
if ($correspond) {
for ($i = 0; $i < count($champs); $i++)
print "champs[$i]=$champs[$i]\n";
} else
print "La chaîne [$chaîne] ne correspond pas au modèle [$modèle]\n";
}
?>
结果:
注释
- 第 3-4 行:此处我们使用正则表达式来提取字符串中的各个字段。正则表达式有助于突破函数 implode 的限制。 其原理是利用函数 preg_match,将一个字符串与另一个名为 modèle 的字符串进行比较:
$correspond = preg_match($modèle, $chaîne, $champs);
如果能在 chaîne 中找到 modèle,则函数 preg_match 返回一个布尔值。 如果可以,则 $champs[0] 代表与该模板对应的子字符串。 此外,如果模型包含括号中的子模型,则 $champs[1] 是 $chaîne 中对应第一个子模型的部分, $champs[2] 是 $chaîne 中对应第二个子模式的部分,以此类推……
让我们来看第一个例子。该模式在第 8 行定义:它表示字符串中任意位置出现的一个或多个(+)数字(\d)。此外,该模式还定义了一个用圆括号包围的子模式。
- 第 10 行:将模式 /(\d+)/(字符串中任意位置的一个或多个数字序列)与字符串 "xyz1234abcd" 进行比对。可以看到子字符串 1234 与该模式匹配。 因此,$champs[0] 等于 "1234"。 此外,该正则表达式包含括号内的子模式。因此 $champs[1] 结果为 "1234"。
- 第 11 行:将正则表达式 /(\d+)/ 与字符串 "12 34" 进行比对。可见子字符串 12 和 34 均符合该正则表达式。比对将在第一个符合正则表达式的子字符串处停止。 因此,我们将得到 $champs[0]=12 和 $champs[1]=12。
- 第12行:将正则表达式 /(\d+)/ 与字符串 "abcd" 进行匹配。未找到匹配项。
下面详细说明代码后续部分中使用的正则表达式:
$modèle = "/^(.*?)(\d+)(.*?)$/";
字符串开头 (^),随后是 0 个或多个 (*) 任意字符 (.),接着是 1 个或多个 (+) 数字,然后再次是 0 个或多个 (*) 任意字符 (.)。 模式 (.*) 表示 0 个或多个任意字符。此类模式将匹配任何字符串。因此,模式 /^(.*)(\d+)(.*)$/ 永远无法被匹配,因为第一个子模式 (.*) 将吞噬整个字符串。 而正则表达式 (.*?)(\d+) 表示 0 个或多个任意字符,直到下一个子模式 (?)(即 \d+)。因此,数字现在不再被 (.*) 模式吞噬。上述正则表达式因此匹配 [début de chaîne (^), une suite de caractères quelconques (.*?), une suite d'un ou plusieurs chiffres (\d+), une suite de caractères quelconques (.*?), la fin de la chaîne ($)]。
$modèle = "/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/";
匹配 [début de chaîne (^), 2 chiffres (\d\d), le caractère / (\/), 2 chiffres, /, 2 chiffres, une suite de 0 ou plusieurs espaces (\s*), la fin de chaîne ($)]
$modèle = "/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/";
[début de chaîne (^), 0 ou plusieurs espaces (\s*), un signe + ou - [+|-] présent 0 ou 1 fois (?), une suite de 0 ou plusieurs espaces (\s*), 1 ou plusieurs chiffres suivis d'un point décimal suivi de zéro ou plusieurs chiffres (\d+\.\d*) ou (|) un point décimal (\.) suivi d'un ou plusieurs chiffres (\d+) ou (|) un ou plusieurs chiffres (\d+), une suite de 0 ou plusieurs espaces (\s*)]。
3.6. 函数参数传递模式 (exemple_11)
<?php
// 参数传递方式
function f(&$i, $j) {
// $i 将通过引用获得
// $j 将按值传递
$i++;
$j++;
print "f[i,j]=[$i,$j]\n";
}
// ----------------------------------------测试
$i = 0;
$j = 0;
// $i 和 $j 按值传递
f($i, $j);
print "test[i,j]=[$i,$j]\n";
?>
结果:
注释
上面的代码展示了向函数传递参数的两种方式。让我们来看以下示例:
- 第 1 行:定义函数 f 的形式参数 $a 和 $b。该函数处理这两个形式参数并返回结果。
- 第 7 行:调用函数 f,并传入两个实际参数 $i 和 $j。 第7行定义了形式参数($a、$b)与实际参数($i、$j)之间的映射关系
- &$a:符号 & 表示形式参数 $a 的值将取自实际参数 $i 的地址。 换言之,$a 和 $i 是指向同一内存位置的两个引用。 操作形式参数 $a 相当于操作实际参数 $i。代码的执行结果也证明了这一点。这种传递方式适用于输出参数以及数组和字典等大容量数据。这种传递方式被称为引用传递。
- $b:形式参数 $b 的值将取自实际参数 $j。这属于值传递。 形式参数和实际参数是两个不同的变量。操作形式参数 $b 不会对实际参数 $j 产生任何影响。代码的执行结果也证明了这一点。这种传递方式适用于输入参数。
- 假设函数 échange 接受两个形式参数 $a 和 $b。 该函数会交换这两个参数的值。因此,在交换调用($i,$j)时,调用方代码期望两个实际参数的值被交换。因此,这些是输出参数(它们会被修改)。因此,应写为:
3.7. 函数返回的结果(exemple_12)
<?php
// 函数返回的结果
// 函数可通过数组返回多个值
list($res1, $res2, $res3) = f1(10);
print "[$res1,$res2,$res3]\n";
$res = f1(10);
for ($i = 0; $i < count($res); $i++)
print "res[$i]=$res[$i]\n";
// 函数可返回伪对象
$res = f2(10);
print "[$res->res1,$res->res2,$res->res3]\n";
// 结束
exit;
// 函数 f1
function f1($valeur) {
// 返回一个数组 ($valeur+1,$aleur+2,$baleur+3)
return array($valeur + 1, $valeur + 2, $valeur + 3);
}
// 函数 f2
function f2($valeur) {
// 返回一个伪对象 ($valeur+1,$aleur+2,$baleur+3)
$res->res1 = $valeur + 1;
;
$res->res2 = $valeur + 2;
$res->res3 = $valeur + 3;
// 返回对象
return $res;
}
?>
结果
注释
- 前面的程序表明,函数 PHP 可以返回一组结果(而非单个结果),形式可以是数组或对象。关于“对象”的概念将在稍后部分详细说明
- 第19-22行:函数f1以数组形式返回多个值
- 第 25-33 行:函数 f2 以对象的形式返回多个值
3.8. 文本文件 (exemple_13)
<?php
// 对文本文件进行顺序处理
// 该文件由多行组成,每行格式为 login:pwd:uid:gid:infos:dir:shell
// 每行数据以“登录名 => uid:gid:infos:dir:shell”的形式存入字典
// 确定文件名
$INFOS = "infos.txt";
// 以新建方式打开
if (!$fic = fopen($INFOS, "w")) {
print "Erreur d'ouverture du fichier $INFOS en écriture\n";
exit;
}
// 生成任意内容
for ($i = 0; $i < 100; $i++)
fputs($fic, "login$i:pwd$i:uid$i:gid$i:infos$i:dir$i:shell$i\n");
// 关闭文件
fclose($fic);
// 利用漏洞 - fgets 保留换行符
// 这可避免在读取空行时获取空字符串
// 以新建方式打开
if (!$fic = fopen($INFOS, "r")) {
print "Erreur d'ouverture du fichier $INFOS en lecture\n";
exit;
}
while ($ligne = fgets($fic, 1000)) {
// 若存在换行符则将其删除
$ligne = cutNewLineChar($ligne);
// 将该行放入数组中
$infos = explode(":", $ligne);
// 获取登录名
$login = array_shift($infos);
// 忽略密码
array_shift($infos);
// 在字典中创建一条条目
$dico[$login] = $infos;
}
// 关闭该表
fclose($fic);
// 利用字典
afficheInfos($dico, "login10");
afficheInfos($dico, "X");
// 结束
exit;
// --------------------------------------------------------------------------
function afficheInfos($dico, $clé) {
// 若存在,则显示字典中与该键关联的值 $dico
if (isset($dico[$clé])) {
// 值存在——是数组吗?
$valeur = $dico[$clé];
if (is_array($valeur)) {
print "[$clé," . join(":", $valeur) . "]\n";
} else {
// $valeur 不是数组
print "[$clé,$valeur]\n";
}
} else {
// $clé 不是字典 $dico 中的键
print "la clé [$clé] n'existe pas\n";
}
}
// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
// 如果存在,则删除 $ligne 的行尾标记
$L = strlen($ligne); // 行长度
while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
$ligne = substr($ligne, 0, $L - 1);
$L--;
}
// 结束
return($ligne);
}
?>
文件 infos.txt:
login0:pwd0:uid0:gid0:infos0:dir0:shell0
login1:pwd1:uid1:gid1:infos1:dir1:shell1
login2:pwd2:uid2:gid2:infos2:dir2:shell2
...
login98:pwd98:uid98:gid98:infos98:dir98:shell98
login99:pwd99:uid99:gid99:infos99:dir99:shell99
结果:
评论
- 第11行:fopen(nom_fichier,"w") 以写入模式打开文件 nom_fichier(w=write)。 如果文件不存在,则创建该文件。如果文件已存在,则清空其内容。如果创建失败,fopen将返回值false。 在语句 if (!$fic = fopen($INFOS, "w")) {…} 中,包含两项连续的操作: 1) $fic=fopen(..) 2) if( ! $fic) {...}
- 第 18 行:fputs($fic,$chaîne) 将 chaîne 写入文件 $fic。
- 第 20 行:fclose($fic) 关闭文件 $fic。
- 第 25 行:fopen(nom_fichier,"r") 以读取模式打开文件 nom_fichier(r=read)。 如果打开失败(文件不存在),fopen 返回值 false。
- 第 29 行:fgets($fic,1000) 读取文件中的下一行,限制为 1000 个字符。 在 while ($ligne = fgets($fic, 1000)) {…} 语句中,包含两个连续的操作:1) $ligne=fgets(...) 2) while ( ! $ligne)。在读取完文件的最后一个字符后,函数 fgets 会将字符串清空,循环 while 随即终止。
- 第 31 行:函数 fgets 读取一行文本,包括换行符。第 70-79 行中的函数 cutNewLineChar 会去除可能存在的换行符。
- 第 72 行:函数 strlen($chaîne) 返回 $chaîne 的字符数。
- 第 73 行:substr($ligne, $position, $taille) 返回 $taille 个字符,这些字符取自 $ligne,从第 $position 个字符开始,其中第一个字符编号为 0。 在 Windows 系统上,换行符为“\r\n”。在 Unix 系统上,换行符为字符串“\n”。
- 第 35 行:函数 array_shift($tableau) 移除 $tableau 的第一个元素,并将其作为结果返回。
- 第 37 行:调用了函数 array_shift($tableau),但忽略了其返回结果
- 第 57 行:函数 is_array($variable) 返回 true(若 $variable 为数组),否则返回 false。
- 第 58 行:函数 join 与之前遇到的函数 implode 功能相同