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>

植入部分

如果您觉得文章不错,可以通过赞助支持我。

如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。

标签: 成品, 源码, 代码段

仅有一条评论

  1. 好长好长

添加新评论