Kirjautuminen

Haku

Tehtävät

Koodivinkit: PHP: Tiedostolista kotisivulle

Kirjoittaja: qalle; viimeksi muokattu 21.10.2018.

Tagit: kielen perusteet, tiedostot

PHP-/HTML-/CSS-sivu, joka tulostaa taulukon samassa hakemistossa olevista tiedostoista, alihakemistoista, niiden ko’oista ja muokkausajankohdista. PHP-koodin alussa on musta ja valkoinen lista, jolla voidaan estää tiettyjen tiedostojen ja alihakemistojen näkyminen taulukossa. Listat tukevat PHP:n fnmatch()-funktion mukaisia korvausmerkkejä (mm. "*").

Demo

Viimeisin muutos: BLACK_AND_WHITE_LIST ja COLUMNS vakioiksi.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>File list</title>
<style type="text/css">
    /* taulukko ja kaikki sen solut */
    table#filelist, table#filelist th, table#filelist td {
        border-style:solid;  /* yhtenäiset reunaviivat */
        border-width:1px;  /* yhden pikselin paksuiset reunaviivat */
    }

    /* taulukko */
    table#filelist {
        border-collapse:collapse;  /* yhdistä toisissaan kiinni olevat reuna-
        viivat toisiinsa (näytä vain yhtenä) */
    }

    /* taulukon kuvaus */
    table#filelist caption {
        caption-side:bottom;  /* muun sisällön alapuolella */
        font-family:sans-serif;  /* pääteviivaton fontti */
        padding:.4em;  /* sisällön etäisyys reunoista 0,4 em-yksikköä */
    }

    /* data-elementti taulukon kuvauksessa */
    table#filelist caption data {
        font-weight:bold;  /* lihavoi */
        white-space:nowrap;  /* älä koskaan jaa usealle riville */
    }

    /* kaikki solut */
    table#filelist th, table#filelist td {
		empty-cells:show;  /* näytä tyhjät solut */
        text-align:left;  /* tasaa sisältö vasemmalle */
        vertical-align:middle;  /* tasaa sisältö pystysuunnassa keskelle */
        padding:.4em .8em;  /* sisällön etäisyys reunoista pystysuunnassa 0,4
        em-yksikköä ja vaakasuunnassa 0,8 em-yksikköä */
    }

    /* otsikkosolut */
    table#filelist th {
        font-family:sans-serif;  /* pääteviivaton fontti */
    }

    /* linkit tiedostoihin ja hakemistoihin */
    table#filelist td.name a {
        font-family:monospace;  /* tasalevyinen fontti */
        font-weight:bold;  /* lihavoi */
        text-decoration:none;  /* poista alleviivaus */
    }

    /* koko-sarakkeen solut */
    table#filelist .size {
		text-align:right;  /* tasaa sisältö oikealle */
    }

    /* tiedostojen koot */
    table#filelist td.size {
        white-space:nowrap;  /* älä koskaan jaa usealle riville */
    }
</style>
</head>
<body>

<?

/*
Seuraava lista määrää, mitkä tiedostot ja alihakemistot näytetään ja mitkä pii-
lotetaan.

Kukin avaimen ja arvon yhdistelmä (avain => arvo) määrittää yhden ehdon:
avain: fnmatch()-funktion mukainen tiedostonimi mahdollisilla jokerimerkeillä;
       poikkeus: kauttaviiva (/) lopussa tarkoittaa, että ehto koskee vain ali-
       hakemistoja; muuten ehto koskee vain tiedostoja
arvo:  True, jos avaimen määrittämät tiedostot/alihakemistot näytetään, tai
       False, jos piilotetaan

Jos sama tiedosto/alihakemisto on määrätty sekä näytettäväksi että piilotetta-
vaksi, sitä ei näytetä.

Jos tiedosto/alihakemisto ei täsmää mihinkään ehtoon, sitä ei näytetä.

Ehtojen järjestyksellä ei ole väliä (paitsi tietysti jos sama avain esiintyy
useasti, jolloin vain sen viimeinen arvo jää voimaan).
*/

const BLACK_AND_WHITE_LIST = [
    "*/" => True,  # hyväksy kaikki hakemistot
    "./" => False,  # paitsi .
    "../" => False,  # ja ..
    "private-*/" => False,  # ja "private-"-alkuiset

    "*.png" => True,  # hyväksy kaikki .png-päätteiset tiedostot
    "salainen.png" => False,  # paitsi salainen.png
    "spede.*" => True,  # hyväksy kaikki "spede."-alkuiset tiedostot
    "??" => True,  # hyväksy kaikki 2-merkkiset tiedostonimet
];

/*
Taulukon sarakkeiden nimet ja kuvaukset.
avain: nimi GET-parametrissa, joka määrää listan järjestyksen
arvo: [
    "class" => CSS-luokan nimi,
    "description" => käyttäjälle näytettävä sarakkeen nimi
]
*/
const COLUMNS = [
    "name" => [
        "class" => "name",
        "description" => "file/subdirectory",
    ],
    "size" => [
        "class" => "size",
        "description" => "size",
    ],
    "modified" => [
        "class" => "last-modified",
        "description" => "last mod&shy;ified",  # &shy; = pehmeä tavuviiva
    ],
];

# tiedostokokojen tuhaterotin (ei tarvitse olla sitova välilyönti; ks. CSS)
const THOUSAND_SEPARATOR = " ";

# päivämäärien ja aikojen muoto; ks. http://php.net/manual/en/function.date.php
const TIME_FORMAT = "Y-m-d H:i:s";

function get_order_argument() {
    # lue lajitteluparametri

    # lue arvo
    $order = $_GET["order"];

    # palauta arvo, jos se löytyy hyväksyttyjen listalta, muuten oletusarvo
    if(array_key_exists($order, COLUMNS)) {
        return $order;
    }
    return array_keys(COLUMNS)[0];
}

function accept_name($name) {
    /* Määrittele, näytetäänkö tiedosto- tai hakemistonimi listalla. (True =
    kyllä, False = ei.) */

    if(is_dir($name)) {
        $name .= "/";
    }

    $onWhitelist = False;

    foreach(BLACK_AND_WHITE_LIST as $pattern => $accept) {
        # FNM_PATHNAME estää jokerimerkkejä vastaamasta mahdollista kauttavii-
        # vaa lopussa
        if(fnmatch($pattern, $name, FNM_PATHNAME)) {
            if($accept) {
                # valkoisella listalla; muista se
                $onWhitelist = True;
            } else {
                # mustalla listalla; hylkää heti
                return False;
            }
        }
    }

    # hyväksy jos ja vain jos oli valkoisella muttei mustalla listalla
    return $onWhitelist;
}

function get_and_sort_files($order) {
    # palauta lajiteltu lista näytettävistä tiedostoista ja alihakemistoista

    # hae tiedostonimet
    $names = array_filter(scandir("."), "accept_name");

    # hae tiedostojen muut tiedot (omiin taulukoihinsa, koska array_multisort()
    # vaatii niin)
    $isDirectory = [];
    $sizes = [];
    $lastModified = [];
    foreach($names as $name) {
        $isDirectory[] = is_dir($name);
        $sizes[] = (is_dir($name) ? 0 : filesize($name));
        $lastModified[] = filemtime($name);
    }

    # lajittele tiedostot
    if($order == "size") {
        array_multisort($isDirectory, SORT_DESC, $sizes, $names, $lastModified);
    } elseif($order == "modified") {
        array_multisort($lastModified, SORT_DESC, $names, $isDirectory, $sizes);
    } else {
        array_multisort($names, $isDirectory, $sizes, $lastModified);
    }

    # sijoittele tiedostojen tiedot uuteen taulukkoon
    $files = [];
    for($i = 0; $i < count($names); $i++) {
        $files[$names[$i]] = [
            "isDirectory" => $isDirectory[$i],
            "size" => $sizes[$i],
            "lastModified" => $lastModified[$i],
        ];
    }

    return $files;
}

function format_order_link($currentOrder, $newOrder, $description) {
    /* Muotoile linkki, joka vaihtaa tiedostojen/alihakemistojen järjestystä.
    $currentOrder: valittuna oleva järjestys
    $newOrder: järjestys, johon tämä linkki vaihtaa
    $description: tämän linkin teksti
    */

    if($newOrder == $currentOrder) {
        # ei linkkiä
        return $description;
    }

    if($newOrder == array_keys(COLUMNS)[0]) {
        # oletusjärjestys
        return sprintf('<a href=".">%s</a>', $description);
    }

    return sprintf('<a href="?order=%s">%s</a>', $newOrder, $description);
}

function my_number_format($size) {
    /* Muotoile kokonaisluku. */

    return number_format($size, 0, ".", THOUSAND_SEPARATOR);
}

function format_item_link($name, $isDirectory) {
    /* Muotoile linkki tiedostoon tai alihakemistoon. */

    return sprintf(
        '<a href="%s">%s%s</a>',
        htmlspecialchars($name),
        htmlspecialchars($name, ENT_NOQUOTES),
        ($isDirectory ? "/" : "")
    );
}

function format_item_size($size, $isDirectory) {
    /* Muotoile tiedoston tai alihakemiston koko. */

    if($isDirectory) {
        return "";
    }

    return sprintf("<data value=%d>%s</data>", $size, my_number_format($size));
}

$order = get_order_argument();
$files = get_and_sort_files($order);
$itemCount = count($files);
$totalFileSize = array_sum(array_column($files, "size"));

/* Tulosta taulukko tiedostoista ja alihakemistoista. */

?>
<table id="filelist">
    <caption>items: <data value=<?=$itemCount?>><?=my_number_format($itemCount)?></data>, total file size: <data value=<?=$totalFileSize?>><?=my_number_format($totalFileSize)?></data></caption>

    <thead>
        <tr>
<? foreach(COLUMNS as $name => $info) { ?>
            <th class="<?=$info["class"]?>"><?=format_order_link($order, $name, $info["description"])?></th>
<? } ?>
        </tr>
    </thead>

    <tbody>

<? foreach($files as $name => $info) { ?>
        <tr>
            <td class="name"><?=format_item_link($name, $info["isDirectory"])?></td>
            <td class="size"><?=format_item_size($info["size"], $info["isDirectory"])?></td>
            <td class="last-modified"><?=date(TIME_FORMAT, $info["lastModified"])?></td>
        </tr>
<? } ?>
    </tbody>
</table>

</body>
</html>

Kommentit

qalle [05.02.2016 21:24:26]

Lainaa #

Demo toimii taas.

qalle [09.07.2017 23:23:43]

Lainaa #

Päivitetty.

Demo (edellisen viestin linkki ei enää toimi)

decoy [04.10.2018 12:25:45]

Lainaa #

kiitoksia, tässä vähän tavaillu php:tä ja oli mukavaksi avuksi tämä .

ja selkeydestä erityinen kunniamaininta ja kiitos.

hyvää alkanutta syksyä jos tännepäin tulet vastauksia lukemaan. vähän on hiljaísta näillä seinillä meno.

qalle [21.10.2018 00:28:00]

Lainaa #

Kiitos. Uusi linkki demoon

Kirjoita kommentti

Muista lukea keskustelun ohjeet.
Tietoa sivustosta