PHP 计算两个文件的相对路径
没错这是我目前的得意之作之一,还特地写了CSS,虽然不怎么好……
所谓使尽浑身解数……
打了草稿,嗯虽然估计过会儿我自己都要看不懂了。(思路,{}
的部分在写下来之后发现了共同点就合并了)
删除 . 和空白数组
比较相同元素,到不同时中断 统计b还有多少元素 不同元素的多少决定了..个数 按序输出不同元素
count数组中元素的大小,取小的那一个作为比较次数 比较一个元素删除一个元素
{如果比完完全符合 则如果b小 返回a剩余元素 b大 返回差集数组计算元素数返回../数
如果不完全符合,则b剩余元素替换为..后加上a剩余元素}
b剩余元素变为../后输出a剩余元素
如果输入文件名a/..
为了找相对路径规律还写了不同的……
$a = '/a/b/c/d/e.png'
$b = '/a/b/c'
相对路径:/d/e$a = '/a/b/c'
$b = '/a/b/c/d'
相对路径 ../$a = '/a/b/c/d/'
$b = '/a/b/12/34/'
相对路径 ../../c/d$a = '/a/b/d'
$b = '/a/b/c/d'
相对路径 ../../d$a = 'a/b/d/e'
$b = 'a/b/c'
相对路径 ../d/e
我们分解下面来说明。
body {
background: #F5F5F5;
}
div {
width: 400px;
height: 250px;
position: absolute;
left: 50%;
top: 50%;
margin-left: -150px;
margin-top: -125px;
background: #eee;
border-radius: 5px;
box-shadow: 0 1px 1px;
}
form {
width: 280px;
margin: 0 auto;
}
h1 {
text-align: center;
}
input[type="text"] {
width: 280px;
}
input[type="text"]:hover {
box-shadow: 0 0 5px #000;
}
input[type="submit"] {
width: 40%;
position: relative;
}
p {
float: none;
text-align: center;
}
CSS部分我们这次定义了input
的样式,可以看出格式是input[type="text"]
,另外使用了刚学会的box-shadow
,详情在:Box-shadow实现常用阴影效果
这次的居中模型使用了:CSS几个竖直与水平居中盒子模型的第一种(当然好像不大会用啊OTZ)
<label>保留文件名:<input type="checkbox" name="file_name" value="yes"></label>
form
中使用了label
,关于这点可以围观:表单input增强用户体验(label和placeholder)
if(!empty($_POST['shot'])) {
$problem = FALSE;
if(empty($_POST['routea'])) {
echo '请输入第一个路径';
$problem = TRUE;
}
if(empty($_POST['routeb'])) {
echo '请输入第二个路径';
$problem = TRUE;
}
if(!$problem) {
$a = explode('/', trim($_POST['routea']));
$b = explode('/', trim($_POST['routeb']));
$check1 = check_route('..', $a);
$check2 = check_route('..', $b);
$a = $check1[0];
$b = $check2[0];
$pass = ($check1[1] && $check2[1]);
if ($pass) {
$a = clean_empty_element('', $a);
$b = clean_empty_element('', $b);
$array1 = search_and_clean('.', $a);
$array2 = search_and_clean('.', $b);
$a = $array1[0];
$b = $array2[0];
$counta = count($a);
$countb = count($b);
$count = ($counta < $countb) ? $counta : $countb;
for ($i=0; $i < $count ; $i++) {
if ($a[$i] == $b[$i]) {
unset($a[$i]);
unset($b[$i]);
} else {
break;
}
}
$route = '';
$countpoint = count($b);
for ($i=0; $i < $countpoint; $i++) {
$route .= '../';
}
if (!empty($a)) {
foreach ($a as $key => $value) {
$route .= $value . '/';
}
}
if(!empty($_POST['file_name'])) {
if (isset($array1[1])) {
$route .= $array1[1];
}
}
if(!empty($route)) {
echo '相对路径为' . $route;
} else {
echo '完全一样哟';
}
} else {
echo '请输入正确的路径';
}
}
}
/* 清除字符串与指定字符串相同的数组元素 */
function clean_empty_element($str, $array) {
foreach ($array as $key => $value) {
if ($array[$key] == $str) {
unset($array[$key]);
}
}
$array = array_values($array);
return $array;
}
/* 清除带指定字符的数组元素*/
function search_and_clean($str, $array) {
$file = NULL;
foreach ($array as $key => $value) {
if (strpos($value, $str)) {
$file = $value;
unset($array[$key]);
}
}
$array = array_values($array);
return array($array, $file);
}
function check_route($str, $array) {
$counter = 0;
$pass = TRUE;
foreach ($array as $key => $value) {
if ($value == $str) {
$counter++;
$array[$key] = '';
if (isset($array[$key - ($counter * 2)])) {
for ($i=0; $i <= ($counter * 2); $i++) {
$array[$key - $i] ='';
}
} else {
$pass = FALSE;
}
} else {
$counter = 0;
}
}
return array($array, $pass);
}
php的部分相当长……
首先毫无疑问验证表单是否提交,然后为了避免用户误输入空格,采取了trim()
,作用是消除两端空格(文件夹里有空格很正常吧……)
扩展阅读:http://www.php.net/manual/zh/function.trim.php
然后再次使用explode()
拆分字符串为数组,在PHP检查IP是否在指定范围内中曾经提到过。
接着检查与简化路径(避免用户输入复杂路径)(这是第二版添加上的T T我根本想不到路径会那么写啊)。
然后清除数组中空白元素和带文件名后缀的元素,之后我们使用了一个三元运算符:$count = ($counta < $countb) ? $counta : $countb;
,因为我们的循环次数取小。
思路基本上同前面写的草稿,发现不同之后用break
立即跳出循环。
依次连接字符串。
最后根据选项选择末尾是否要添加文件名。
这里我写了三个很有用的函数,具有推广性,应此在函数中变量为两个,一个是字符串,另一个是数组名。
/* 清除字符串与指定字符串相同的数组元素 */
function clean_empty_element($str, $array) {
foreach ($array as $key => $value) {
if ($array[$key] == $str) {
unset($array[$key]);
}
}
$array = array_values($array);
return $array;
}
如果发现了和指定字符串完全相同的数组元素,就unset()
释放(销毁)它,全部循环完毕之后用array_value()
重新建立索引。
/* 清除带指定字符的数组元素*/
function search_and_clean($str, $array) {
$file = NULL;
foreach ($array as $key => $value) {
if (strpos($value, $str)) {
$file = $value;
unset($array[$key]);
}
}
$array = array_values($array);
return array($array, $file);
}
这里使用了strpos()
,作用是返回字符串中指定字符串的位置
,这里我们输入了一个'.'
,又恰好如果是..
的话位置是0
,布尔值是FALSE
,被排除在外了,所以如果想要算上所有的位置,还是得用isset()
一类的。同样的销毁,重建数组。
我们这里还设定了一个$file
,为了便于输出文件名,实现把$file
储存,但$file
不存在导出会报错,所以设定了一个NULL
返回不能返回多值,只能以数组形式返回了,关于返回值,在PHP变量命名规则与范围提及。
function check_route($str, $array) {
$counter = 0;
$pass = TRUE;
foreach ($array as $key => $value) {
if ($value == $str) {
$counter++;
$array[$key] = '';
if (isset($array[$key - ($counter * 2)])) {
for ($i=0; $i <= ($counter * 2); $i++) {
$array[$key - $i] ='';
}
} else {
$pass = FALSE;
}
} else {
$counter = 0;
}
}
return array($array, $pass);
}
这是我写过最神奇的东西,曾经想过unset()
加指针移动,未果,报错,于是就产生了这货,这货配合第一个函数使用就能达到简化目录的效果,它的拓展意义不大,主要是检索$str
连续出现数量,然后成双替代,扩宽范围,如果下一个不是$str
的时候把计数器清零,另外如果目录../
出现太多,则会有相应提示。
完整版源代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
body {
background: #F5F5F5;
}
div {
width: 400px;
height: 250px;
position: absolute;
left: 50%;
top: 50%;
margin-left: -150px;
margin-top: -125px;
background: #eee;
border-radius: 5px;
box-shadow: 0 1px 1px;
}
form {
width: 280px;
margin: 0 auto;
}
h1 {
text-align: center;
}
input[type="text"] {
width: 280px;
}
input[type="text"]:hover {
box-shadow: 0 0 5px #000;
}
input[type="submit"] {
width: 40%;
position: relative;
}
p {
float: none;
text-align: center;
}
</style>
<title>Route</title>
</head>
<body>
<div>
<h1>相对路径生成器</h1>
<p>将生成第二个文件相对于第一个的相对路径</p>
<form action="route.php" method="post">
<input type="text" name="routea" placeholder="输入第一个文件路径如/a/b/c/d/e.php"><br/>
<input type="text" name="routeb" placeholder="输入第二个文件路径如/a/b/12/34/c.php"><br/>
<label>保留文件名:<input type="checkbox" name="file_name" value="yes"></label>
<input type="hidden" name="shot" value="shot">
<input type="submit" value="运算">
</form>
<p>
<?php
if(!empty($_POST['shot'])) {
$problem = FALSE;
if(empty($_POST['routea'])) {
echo '请输入第一个路径';
$problem = TRUE;
}
if(empty($_POST['routeb'])) {
echo '请输入第二个路径';
$problem = TRUE;
}
if(!$problem) {
$a = explode('/', trim($_POST['routea']));
$b = explode('/', trim($_POST['routeb']));
$temp1 = check_protocol('http:', $a);
$temp2 = check_protocol('http:', $b);
$protocol_a_http = $temp1[1];
$protocol_b_http = $temp2[1];
$a = $temp1[0];
$b = $temp2[0];
$temp1 = check_protocol('file:', $a);
$temp2 = check_protocol('file:', $b);
$protocol_a_file = $temp1[1];
$protocol_b_file = $temp2[1];
$a = $temp1[0];
$b = $temp2[0];
$temp1 = check_protocol('ftp:', $a);
$temp2 = check_protocol('ftp:', $b);
$protocol_a_ftp = $temp1[1];
$protocol_b_ftp = $temp2[1];
$a = $temp1[0];
$b = $temp2[0];
$pass4 = TRUE;
if ($protocol_a_http || $protocol_b_http || $protocol_a_file || $protocol_b_file || $protocol_a_ftp || $protocol_b_ftp) {
switch ($protocol_a_http || $protocol_b_http || $protocol_a_file || $protocol_b_file || $protocol_a_ftp || $protocol_b_ftp) {
case ($protocol_a_http&&$protocol_b_http):
if($a[1] !== $b[1]) {
echo '你输入的域名不相同<br/>';
$pass4 = FALSE;
}
break;
case ($protocol_a_ftp&&$protocol_b_ftp):
if($a[1] !== $b[1]) {
echo '你输入的FTP地址不相同<br/>';
$pass4 = FALSE;
}
break;
case ($protocol_a_file&&$protocol_b_file):
break;
default:
echo "协议不一致<br/>";
$pass4 = FALSE;
break;
}
}
$check1 = check_route('..', $a);
$check2 = check_route('..', $b);
$a = $check1[0];
$b = $check2[0];
$pass1 = ($check1[1] && $check2[1]);
$pass2 = (search(' ', $a) && search(' ', $b));
$pass3 = (search('.', $a) && search('.', $b));
if ($pass1 && $pass2 && $pass3 && $pass4) {
$a = clean_empty_element('', $a);
$b = clean_empty_element('', $b);
$array1 = search_and_clean_last('.', $a);
$array2 = search_and_clean_last('.', $b);
$a = $array1[0];
$b = $array2[0];
$counta = count($a);
$countb = count($b);
$count = ($counta < $countb) ? $counta : $countb;
for ($i=0; $i < $count ; $i++) {
if ($a[$i] == $b[$i]) {
unset($a[$i]);
unset($b[$i]);
} else {
break;
}
}
$route = '';
$countpoint = count($b);
for ($i=0; $i < $countpoint; $i++) {
$route .= '../';
}
if (!empty($a)) {
foreach ($a as $key => $value) {
$route .= $value . '/';
}
}
if(!empty($_POST['file_name'])) {
if (isset($array1[1])) {
$route .= $array1[1];
}
}
if(!empty($route)) {
echo '相对路径为' . $route;
} else {
echo '完全一样哟';
}
} else {
echo '请输入正确的路径';
}
}
}
/* 检查协议 */
function check_protocol($protocol, $array) {
$check = FALSE;
if ($array[0] === $protocol) {
$check = TRUE;
unset($array[0]);
$array = array_values($array);
}
return array($array, $check);
}
/* 检查数组中是否含指定字符串 */
function search($str, $array) {
$pass = TRUE;
foreach ($array as $key => $value) {
if ($value == $str) {
$pass = FALSE;
break;
}
}
return $pass;
}
//只检查最后一个的函数 其他当作文件名来处理
function search_and_clean_last($str, $array) {
$file = NULL;
$counter = count($array);
if(strpos($array[$counter - 1], $str)) {
$file = $array[$counter - 1];
unset($array[$counter - 1]);
}
$array = array_values($array);
return array($array, $file);
}
/* 清除字符串与指定字符串相同的数组元素 */
function clean_empty_element($str, $array) {
foreach ($array as $key => $value) {
if ($array[$key] == $str) {
unset($array[$key]);
}
}
$array = array_values($array);
return $array;
}
/* 清除带指定字符的数组元素*/
function search_and_clean($str, $array) {
$file = NULL;
foreach ($array as $key => $value) {
if (strpos($value, $str)) {
$file = $value;
unset($array[$key]);
}
}
$array = array_values($array);
return array($array, $file);
}
function check_route($str, $array) {
$counter = 0;
$pass = TRUE;
foreach ($array as $key => $value) {
if ($value == $str) {
$counter++;
$array[$key] = '';
if (isset($array[$key - ($counter * 2)])) {
for ($i=0; $i <= ($counter * 2); $i++) {
$array[$key - $i] ='';
}
} else {
$pass = FALSE;
}
} else {
$counter = 0;
}
}
return array($array, $pass);
}
?>
</p>
</div>
</body>
</html>
植入部分
如果您觉得文章不错,可以通过赞助支持我。
如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。
好长好长