Tallenna tiedosto ".php" -päätteellä.
<?php
//***************************************************************************************************
// Latauslaskuri ja Lataushistorian tarkastelu PHP-ohjelma
// [Jokaisen tiedon hieman hyödyllinen kirja]
// Minna no Chishiki Chotto Benricho
// みんなの知識 ちょっと便利帳
// https://www.benricho.org/Tips/download_history/
// Julkaistu: 25. helmikuuta 2024
//
// Yleiskatsaus:
// Tämä ohjelma on järjestelmä tiedostojen lataushistorian seurantaan, jossa on käyttäjän todennusominaisuudet.
// Siihen sisältyy ominaisuuksia kuten syötetietojen sanitointi, loki-tiedostojen luonti ja lataustilastojen näyttö.
// Voit käyttää sitä vapaasti, mukaan lukien koodin muokkaaminen ja sivun suunnittelun muuttaminen.
//
// Huomautus:
// Ennen kuin lähetät sivun, jossa on latauslinkkejä, varmista, että tämän tiedoston "$targetFiles = array()" -osio on määritetty,
// ja lähetä tämä sivu ennen sivua, jossa on latauslinkit.
// Jos näin ei tehdä, käyttäjät eivät ehkä pysty lataamaan, koska tämä sivu asettaa ja viittaa lataukseen tarkoitettuihin tiedostoihin.
//
// Asetukset ja huomautukset:
// ① Salasana on asetettu arvoon "admin", mutta vaihda se haluamaasi merkkijonoon.
// ② "log" -hakemisto loki-tiedostojen tallentamiseksi luodaan automaattisesti ensimmäisen lähetyksen yhteydessä.
// Jos kohtaat kuitenkin viestejä kuten "hakemistoa ei löydy", lähetä se erikseen.
// ③ Alkuperäisessä lähetyksessä historia näyttää "päiväyksen" ja numeron "0".
// Tämä johtuu siitä, että loki-tiedostot, kuten "count_1.log", jossa on lähetyksen päivämäärä, luodaan samanaikaisesti automaattisesti luotuun "log" -hakemistoon.
// Jos tämä huolestuttaa, käy etäpalvelimella, lataa tiedostot kuten "count_1.log", poista tiedot ja lähetä ne uudelleen.
// ④ Näytettäessä useita taulukoita sivulla historiassa voit valita, pidätkö taulukon, joka on asetettu [$targetFiles = array], vai näytetäänkö ne aikajärjestyksessä.
// ⑤ Historianäytössä voit valita, sisällytetäänkö verkkotunnus 1) tiedoston näyttämiseen vai 2) vain tiedoston nimeen.
//
// [Latauslinkin muoto sivulla, jossa on latauslinkkejä]
// [Esimerkki] <a href="/download_history/count.php?download=Rekisteröity Numero" download="LadattuTiedostonNimi.zip" target="_blank">[Mikä tahansa merkkijono]</a>
// ① Säädä numeroa "download=1" vastaamaan asetettua "$targetFiles = array()".
// ② Säädä polku vastaamaan sivuasi.
//
// [Koodi (JavaScript) historian yhden rivin näyttämiseen sivulla, jossa latauslinkki sijaitsee]
// [Esimerkki] <script type="text/javascript" src="/download_history/count.php?dsp_count=1&day_dsp=on"></script>
// ① Säädä numeroa "dsp_count=1" vastaamaan asetettua "$targetFiles = array()".
// ② Jos poistat "&day_dsp=on," näytetään vain "kokonaismäärä" ilman "tänään" ja "eilen" näyttöä.
// ③ Säädä polku vastaamaan sivuasi.
//***************************************************************************************************
// Asetukset ladattaville tiedostoille. Jos tiedostoja on useita, lisää ne muodossa '2', '3', '4' jne. Myös '0' on kelvollinen.
// Käytä protokollaa "http:" tai "https:".
$targetFiles = array(
'1' => 'SinunURL/OmatTiedostoNimi.zip',
'2' => 'SinunURL/OmatTiedostoNimi.pdf',
'3' => 'SinunURL/OmatTiedostoNimi.pdf',
'4' => 'SinunURL/OmatTiedostoNimi.pdf',
);
// Aseta merkistökoodaus HTML-tulostukseen
header("Content-Type: text/html; charset=utf-8");
// Merkistökoodaus lataushistorian näyttämiseen tarkoitetulla sivulla
$encodingType = 'UTF-8';
// Määritä käyttäjän todennustiedot ja muut asetukset
$userid = 'admin'; // Käyttäjätunnus (korvaa 'admin' millä tahansa merkkijonolla)
$password = 'admin'; // Salasana (korvaa 'admin' millä tahansa merkkijonolla)
$hashedPassword = password_hash($password, PASSWORD_DEFAULT); // Käytä password_hash() -funktiota hash-arvon luomiseen
$dataLogDir = 'log/'; // 'log' -hakemisto luodaan automaattisesti tämän ohjelman toimesta. Jos sitä ei ole luotu, lähetä erikseen hakemisto nimeltään 'log'
// Valitse, sisällytetäänkö verkkotunnus tiedostonimen näyttämiseen vai ei
$includeDomain = 1; // 1: Näytä sisältäen verkkotunnuksen, 0: Näytä vain tiedoston nimi
// Valitse, korvata anko alkuperäinen taulukko uudella aakkosjärjestyksessä olevalla uudella, kun näytetään useita taulukoita sivulla
$sortTables = 1; // 1: Lajittele, 0: Älä lajittele
$dir = 'log'; // Hakemisto lokitiedostojen ja lataushistorian tallentamiseen
// Hanki sivustosi verkkotunnus
$domain = $_SERVER['HTTP_HOST'];
// Istunnonhallinta: Estä istunnon kaappaus ja käytä session_set_cookie_params() -funktiota
session_set_cookie_params(0, '/', $domain, true, true); // Aseta HttpOnly- ja Secure-liput
session_start();
if (!isset($_SESSION['auth'])) {
$_SESSION['auth'] = FALSE;
}
// Salasanan hajautus: Käytä password_needs_rehash() -funktiota
if (password_needs_rehash($hashedPassword, PASSWORD_DEFAULT)) {
$newHashedPassword = password_hash($password, PASSWORD_DEFAULT);
// Tallenna uusi hash-arvo tietokantaan jne.
}
// Luo hakemisto, jos sitä ei ole olemassa
if (!is_dir($dir)) {
if (mkdir($dir, 0755, true)) {
} else {
// Näytä virhe, jos hakemiston luonti epäonnistuu
echo 'Luo "' . $dataLogDir . '" -hakemisto ja lähetä se erikseen.';
}
}
// Tarkista, onko lokihakemisto kirjoitettavissa
if (!is_writable($dataLogDir)) {
die('"' . $dataLogDir . '" -hakemistoa ei ole tai siihen ei ole kirjoitusoikeuksia. Luo hakemisto ja aseta käyttöoikeudet asianmukaisesti (esim. 755).');
}
// Hanki peruspäivä ja eilisen päivän päivä
$baseDay = date("Y/m/d");
$yesterday = date("Y/m/d", strtotime("-1 day"));
// Funktio päivän viikonpäivän hakemiseksi päivämäärästä
function getDayOfWeek($date)
{
$dayOfWeek = date('w', strtotime($date));
$weekDays = array('Su', 'Ma', 'Ti', 'Ke', 'To', 'Pe', 'La');
return $weekDays[$dayOfWeek];
}
// Aseta tiedostopolku kullekin kohdetiedostolle ja luo loki-tiedosto, jos sitä ei ole olemassa
foreach ($targetFiles as $key => $val) {
$filePath[$key] = $dataLogDir . "count_" . $key . ".log";
// Luo loki-tiedosto, jos sitä ei ole olemassa
if (!file_exists($filePath[$key])) {
createLogFile($filePath[$key]);
}
}
// Hanki tiedostopolut ja niiden viimeiset päivityspäivämäärät (järjestetty päivämäärän laskevaan järjestykseen)
$filePathsAndDates = array();
foreach ($filePath as $key => $path) {
if (file_exists($path)) {
$filePathsAndDates[$key] = filemtime($path);
} else {
// Tulosta tämä virhe lokiin ja päätä jatkaako vai keskeytetäänkö prosessi
echo "Virhe: Tiedostoa ei löydy - $path<br>";
}
}
// Lajittele päivämäärän mukaan laskevassa järjestyksessä (uusin päivämäärä ensin)
arsort($filePathsAndDates);
// Rakenna uudelleen järjestetty tiedostopolkujen taulukko
$sortedFilePaths = array();
foreach ($filePathsAndDates as $key => $date) {
$sortedFilePaths[$key] = $filePath[$key];
}
// Valitse ehdollisesti, käytetäänkö lajiteltuja polkuja lajittelussa
$filePath = ($sortTables) ? $sortedFilePaths : $filePath;
// Palauta JavaScript-koodi asiakkaalle (latausmäärien dynaaminen näyttäminen)
if (isset($_GET['dsp_count'])) {
header("Content-type: application/x-javascript");
// Aseta otsikko JavaScript-tiedostoksi
if (!preg_match("/^[0-9]+$/", $_GET['dsp_count'])) {
echo "document.write(\"Parametrin on oltava puolileveä numero\")";
exit();
}
$dspCountNo = $_GET['dsp_count'];
if (!file_exists($filePath[$dspCountNo])) {
createLogFile($filePath[$dspCountNo]);
}
$line = file($filePath[$dspCountNo]);
$total = 0;
$todayCount = 0;
$yesterdayCount = 0;
foreach ($line as $val) {
$valArray = explode(',', $val);
$total += trim($valArray[1]);
if (strpos($valArray[0], $baseDay) !== false) {
$todayCount = trim($valArray[1]);
}
if (strpos($valArray[0], $yesterday) !== false) {
$yesterdayCount = trim($valArray[1]);
}
}
// Jos päivämääränäyttöasetus on PÄÄLLÄ, näytetään päivämäärän mukana
if (isset($_GET['day_dsp']) && $_GET['day_dsp'] == 'on') {
$countDsp = <<<EOF
document.write('<div class="counter_inpage">Kokonaismäärä: <strong>{$total}</strong>[<span class="count_today">Tänään : <strong>{$todayCount}</strong></span> <span class="count_yesterday">Eilen : <strong>{$yesterdayCount}</strong></span>]</div>')
EOF;
} else {
// Jos päivämääränäyttöasetus on POIS, näytetään vain kokonaismäärä
$countDsp = <<<EOF
document.write('<p class="counter_inpage">Kokonaismäärä: {$total}</p>')
EOF;
}
// Jos merkistökoodaus ei ole UTF-8, muunna
if ($encodingType != 'UTF-8') $countDsp = mb_convert_encoding($countDsp, "$encodingType", 'UTF-
8');
echo $countDsp;
exit();
}
// Tiedoston latauspyyntöön liittyvä käsittely
if (isset($_GET['download'])) {
$fileId = $_GET['download'];
// Poistu, jos tiedoston tunniste ei ole numero tai jos tiedoston tunniste ei ole olemassa
if (!preg_match("/^[0-9]+$/", $fileId) || !isset($filePath[$fileId])) {
exit('Virheellinen numeerinen parametri');
}
// Avaa tiedosto ja lukitse se
$fp = fopen($filePath[$fileId], "rb+");
if (!$fp) {
exit('Tiedoston avaaminen epäonnistui');
}
flock($fp, LOCK_EX);
// Lue loki-tiedosto ja tallenna se taulukkoon
$line = array();
while (($data = fgets($fp)) !== false) {
$line[] = $data;
}
// Tyhjennä tiedosto ja lisää uusi päivämäärärivi alkuun
ftruncate($fp, 0);
rewind($fp);
// Lisää uusi päivämäärärivi alkuun, jos sitä ei ole olemassa
if (strpos($line[0], $baseDay) === false) {
$writeLine = $baseDay . ',1' . "\n";
fwrite($fp, $writeLine);
}
// Käsittele jokaista riviä tiedostossa
foreach ($line as $val) {
// Lisää latausten määrää nykyisen päivän osalta
if (strpos($val, $baseDay) !== false) {
$valArray = explode(',', $val);
$valArray[1] = rtrim($valArray[1], "\n") + 1;
$val = $valArray[0] . ',' . $valArray[1] . "\n";
}
fwrite($fp, $val);
}
// Tyhjennä puskuri ja vapauta lukko
fflush($fp);
flock($fp, LOCK_UN);
// Sulje tiedosto
fclose($fp);
// Tyhjennä tulospuskuri
ob_end_clean();
// Suorita tiedoston lataus
header("Location: {$targetFiles[$fileId]}");
exit();
} else {
// Aloita istunto, tuhoa istunto, jos uloskirjautuminen on pyydetty
session_start();
if (isset($_GET['logout'])) {
$_SESSION = array();
session_destroy();
}
$loginError = '';
if (!isset($_SESSION['auth'])) {
$_SESSION['auth'] = FALSE;
}
// Käytä salasanan hajautusfunktiota hajautusarvon generoimiseksi
// Kirjautumiskäsittely
if (isset($_POST['userid']) && isset($_POST['password'])) {
// Vertaa hajautusarvoja todennusta varten
if ($_POST['userid'] === $userid && password_verify($_POST['password'], $hashedPassword)) {
$oldSid = session_id();
session_regenerate_id(TRUE);
if (version_compare(PHP_VERSION, '5.1.0', '<')) {
$path = session_save_path() != '' ? session_save_path() : '/tmp';
$oldSessionFile = $path . '/sess_' . $oldSid;
if (file_exists($oldSessionFile)) {
unlink($oldSessionFile);
}
}
$_SESSION['auth'] = TRUE;
} else {
// Käsittely epäonnistuneelle todennukselle
$_SESSION['auth'] = FALSE;
$loginError = '<div style="text-align: center; color: crimson;">Virheellinen käyttäjätunnus tai salasana.</div>';
}
}
// Jos todennus ei onnistu, näytä kirjautumisnäyttö
if ($_SESSION['auth'] !== TRUE) {
?>
<!DOCTYPE html>
<html lang="fi">
<head>
<meta charset="utf-8">
<meta name="robots" content="NOINDEX,NOFOLLOW">
<title>Lataushistoria Kirjautumisnäyttö</title>
<!-- Kirjautumisnäytön tyylit (muokattavissa tarvittaessa) -->
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0px;
padding: 0px;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
form {
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
}
label {
display: block;
margin-bottom: 8px;
}
input {
font-size: 18px;
width: 100%;
padding: 8px;
margin-bottom: 16px;
box-sizing: border-box;
}
button {
font-size: 16px;
background-color: #4caf50;
color: #fff;
padding: 10px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.logintitle {
text-align: center;
font-size: 18px;
font-weight: bold;
}
.logininfo {
text-align: center;
}
.passwordshow {
font-size: 14px;
font-weight: bold;
color: darkgray;
text-align: center;
}
.center-container {
display: inline-block;
margin: 0 5px 0 0;
}
</style>
</head>
<body>
<div id="login_form">
<form action="<?php echo $fileName; ?>?mode=download" method="post">
<p class="logintitle">【Näytä Lataushistoria】</p>
<?php if (isset($loginError)): ?>
<!-- Näytä virheviesti, jos $loginError-muuttuja on asetettu -->
<p style="color: crimson;"><?php echo $loginError; ?></p>
<?php endif; ?>
<label for="userid">Käyttäjätunnus:</label>
<input type="text" id="userid" name="userid" required>
<label for="password">Salasana:</label>
<input type="password" id="password" name="password" required>
<?php
// Olettaen, että $showPassword on PHP-muuttuja, joka määrittää, näytetäänkö salasana aluksi
echo '<label class="passwordshow" for="showPassword">[Näytä Salasana]<div class="center-container"><input type="checkbox" id="showPassword" onchange="togglePasswordVisibility()" ' . ($showPassword ? 'checked' : '') . '></div></label>';
?>
<button type="submit" name="login_submit">Kirjaudu</button>
</form>
</div>
<!-- Kontrolloi salasanan näkyvyyttä -->
<script>
function togglePasswordVisibility() {
var passwordInput = document.getElementById('password');
var showPasswordCheckbox = document.getElementById('showPassword');
if (showPasswordCheckbox.checked) {
// Jos valittu, salasana näytetään
passwordInput.type = 'text';
} else {
// Poista valinta piilottaaksesi salasanan
passwordInput.type = 'password';
}
}
</script>
</body>
</html><?php
exit();
} else {
// Jos kirjautunut sisään, näytä lataushistorian sivu
?>
<!DOCTYPE html>
<html lang="fi">
<head>
<meta charset="utf-8">
<meta name="robots" content="NOINDEX,NOFOLLOW">
<title>Lataushistoria</title>
<!-- Lataushistorian katselun tyyli (muokattavissa tarvittaessa) -->
<style>
body {
font-family: 'Hiragino Kaku Gothic ProN', 'Hiragino Kaku Gothic ProN W3', Meiryo, Osaka, 'MS PGothic', arial, helvetica, sans-serif;
}
.log_title {
font-size: 16px;
font-weight: bold;
color: brown;
margin: 0px 0px 15px 10px;
}
.get_url {
font-size: 13px;
font-weight: bold;
padding: 8px 0;
color: brown;
background-color: lightgoldenrodyellow;
}
.log_table{
float:left;
width: 300px;
border: #CCC 1px solid;
border-radius: 5px;
margin: 0px 0px 5px 10px;
padding: 0px 5px 5px 5px;
word-break: break-all;
}
table {
width: 100%;
border-collapse: collapse;
}
td,
th {
padding: 5px 10px;
border: 1px solid #999;
text-align: right;
font-size: 90%;
}
th {
background: lavenderblush;
text-align: center;
font-weight: normal;
}
.tableheader {
background: lavender;
text-align: center;
font-weight: bold;
white-space: nowrap;
}
.total{
float:left;
margin: -25px 0px 0px 10px;
}
.counter_inpage{
margin: 15px 0px 8px 0px;
}
.bold{
font-weight: bold;
}
</style>
</head>
<body>
<div class="log_title">【Lataushistoria】 【<a href="?logout=true">Kirjaudu Ulos</a>】</div>
<?php foreach($filePath as $key => $val){ ?>
<div class="log_table">
<div class="get_url"><?php echo $includeDomain ? $targetFiles[$key] : basename($targetFiles[$key]); ?></div>
<table align="center">
<tr>
<th class="tableheader">Päivämäärä</th>
<th class="tableheader">Lataukset</th>
</tr>
<?php
$totalDownload = 0;
// Lue vain, jos tiedosto on olemassa
if (file_exists($val)) {
$line = file($val);
foreach ($line as $lineVal) {
$lineArray = explode(',', $lineVal);
// Tarkista, onko $lineArray[1] numeerinen arvo
$numericValue = filter_var($lineArray[1], FILTER_VALIDATE_FLOAT);
if ($numericValue !== false) {
$totalDownload += $numericValue;
?>
<tr>
<th nowrap><?php echo $lineArray[0] . ' (' . getDayOfWeek($lineArray[0]) . ')'; ?></th>
<td class="bold" nowrap><?php echo $lineArray[1]; ?></td>
</tr>
<?php
}
}
}
?>
<tr>
<th colspan="2" class="bold">Kokonaismäärä: <?php echo $totalDownload;?></th>
</tr>
</table>
</div>
<?php
}
}
}
?>
</body>
</html><?php
// Funktio kaikkien taulukon elementtien puhdistamiseen
function sanitize($arr)
{
// Jos se on taulukko, sovelleta puhdistusta rekursiivisesti
if (is_array($arr)) {
return array_map('sanitize', $arr);
}
// Poista NULL-merkit merkkijonoista
return str_replace("\0", "", $arr);
}
// Luo uusi loki-tiedosto, jos sitä ei ole olemassa
function createLogFile($filePath)
{
$baseDay = date("Y/m/d");
$fp = fopen($filePath, "a+b");
if ($fp) {
flock($fp, LOCK_EX);
ftruncate($fp, 0);
rewind($fp);
fwrite($fp, "$baseDay,0");
fflush($fp);
flock($fp, LOCK_UN);
fclose($fp);
// Aseta tiedoston käyttöoikeudet
chmod($filePath, 0666);
} else {
}
}