robsite

ChunkMail

DailyLit ist klasse. Sendet einem täglich einen kleinen Teil eines langen Buches per Mail oder RSS. E-Mails liest man eh; warum so also nicht auch das Buch, das seit 3 Wochen auf dem Nachttisch verstaubt? Nachteil von DailyLit: Keine eigenen Texte hochladbar.

Drum schrieb ich mir gestern ein simples kleines PHP-Script, das einem auf Anfrage den nächsten Teil eines langen Textes per Mail schickt. Mehr nicht. Keine User-Accounts, multiplen Dateien, Admin-Interfaces etc.
Wer es gebrauchen kann:

<?
/*
ChunkMail
(c) Robert Gerlach 2012 - robsite.de

Sends and displays chunks of a long text per mail. Inspired by DailyLit.com

Usage:

1. Upload chunkmail.php to a PHP capable web server

2. Put a long text file in the same folder as chunkmail.php

3. Edit $config below with the name of your long text file.

4. Make the chunkmail folder writeable by PHP (so chunkmail can create meta_$longTextFile, which stores the already mailed pages)

5. Call chunkmail.php:        
    chunkmail.php           - Display smallest unread page. Mail it, if it hasn't been mailed yet.
    chunkmail.php?page=123  - Display page 123. Mail it, if it hasn't been mailed yet.
    chunkmail.php?reset     - Reset list of mailed pages. Display page 1, mail it.

    To send you the newest page daily at 6:00, use cron:
    > crontab -e
    0 6 * * * wget http://example.com/where/chunkmail/is/chunkmail.php > /dev/null

    
    
Optional: Secure chunkmail folder via .htaccess on Apache:

1. Create a .htpasswd file somewhere your webserver can't access it. You can generate the password with tools like
    - http://www.4webhelp.net/us/password.php
    - http://www.htaccesstools.com/htpasswd-generator/

2. Create .htaccess in the chunkmail folder
    AuthUserFile /absolute/path/to/.htpasswd
    AuthType Basic
    AuthName "ChunkMail"
    Require valid-user    

3. Modify wget in crontab to use HTTP-Authentication:
    wget http://YOUR_USERNAME:YOUR_PASSWORD@example.com/where/chunkmail/is/chunkmail.php > /dev/null


License: WSCECPUCYUS - Wear a Slice of Cheese for Every CPU Core You Use the Software on
*/

$config = array(
    'longTextFile'      => "longtextislong.txt",        // Your long text file
    'chunkSize'         => 3*1024,                      // Chunk size in bytes
    'chunkPadding'      => 512,                         // Chunk padding in bytes. Displays a bit of the previous chunk, so you know where you left off.
    'receiver'          => 'you@somewhere.com'          // Receiver email
);

$serverURL = $_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'];
if ($_SERVER['HTTPS']) {
    $serverURL = 'https://'.$serverURL;
} else {
    $serverURL = 'http://'.$serverURL;
}

// File with sent page numbers, comma separated
$metaFile = 'meta_'.$config['longTextFile']; 

// Get text length and pages length
$longText = file_get_contents($config['longTextFile']);
$longTextLength = strlen($longText);
$pagesLength = floor($longTextLength / $config['chunkSize']);
if ($pagesLength < 1) {
    $pagesLength = 1;
}

// Reset sent pages. Start from the beginning
$reset = false;
if (isset($_GET['reset'])) {
    file_put_contents($metaFile, "");
    $reset = true;
}

$currentPage = 0;
$sentPages = array(); // all the already sent pages

if (file_exists($metaFile)) {    
    $fileContents = file_get_contents($metaFile);
    
    if (strlen($fileContents) > 0) {
        $sentPagesFromFile = explode(",", $fileContents);
    } 
    
    if (is_array($sentPagesFromFile)) {        
        $sentPages = $sentPagesFromFile;
    }
}

// Get current page (starting with 0). Either the ?page, or the smallest unread page
if (isset($_GET['page'])) {
    $currentPage = $_GET['page']-1;    

} else {
    // Smallest unread page or last page
    $currentPage = $pagesLength - 1;
    for ($i = 0; $i < $pagesLength; $i++) {
        if (!in_array($i."", $sentPages)) {
            $currentPage = $i."";
            break;
        }
    }
}

if ($currentPage >= $pagesLength) {
    $currentPage = $pagesLength - 1;
} else if ($currentPage < 0) {
    $currentPage = 0;
}

// Get text chunk for this page plus a little padding to ease you into the text
$ratio = $currentPage / $pagesLength;
$chunkStart = $ratio * $longTextLength;
$chunkLength = $longTextLength / $pagesLength;
$chunk = substr($longText, $chunkStart, $chunkLength); // don't bother with cutting off words. That's what the padding is for.

$paddingChunkStart = $chunkStart - $config['chunkPadding'];
if ($paddingChunkStart < 0) {
    $paddingChunkStart = 0;
}
$paddingChunkLength = $chunkStart - $paddingChunkStart;
if ($paddingChunkLength > 0) {
    $paddingChunk = substr($longText, $paddingChunkStart, $paddingChunkLength);
} else {
    $paddingChunk = '';
}

$nextPage = $currentPage + 1;
if ($nextPage >= $pagesLength) {
    $nextPage = $pagesLength - 1;
}

$previousPage = $currentPage - 1;
if ($previousPage < 0) {
    $previousPage = 0;
}

// Send current chunk per mail, but only once
$wasSent = false;
if (!in_array($currentPage, $sentPages)) {
    
    $to = $config['receiver'];
    $subject = $config['longTextFile'] . " ".($currentPage+1) . "/" . $pagesLength . " — ChunkMail";
    
    $message = $subject . "\n\n";
    $message .= $paddingChunk."\n\n--------\n\n".$chunk;
    $message .= "\n\n\n";
    $message .= "Send next unread page: " . $serverURL."\n\n";
    $message .= "First Page: " . $serverURL."?page=1\n";
    $message .= "Previous Page: " . $serverURL."?page=".($previousPage + 1)."\n";
    $message .= "Next Page: " . $serverURL."?page=".($nextPage + 1)."\n";
    $message .= "Last Page: " . $serverURL."?page=".($pagesLength)."\n\n";
    $message .= "Reset mailed pages: " . $serverURL."?reset";
    
    $headers =  'From: chunkmail@'.$_SERVER['SERVER_NAME'] . "\r\n" . 
                'Reply-To: chunkmail@'.$_SERVER['SERVER_NAME'] . "\r\n";                    
    
    mail($to, $subject, $message, $headers);    
    
    $sentPages[] = $currentPage;
    $wasSent = true;
}

sort($sentPages); // unnecessary but nice

file_put_contents($metaFile, implode(",", $sentPages));

?><!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title><?= $config['longTextFile']." ". ($currentPage+1) . "/" . $pagesLength?> — ChunkMail</title>

        <style type="text/css" media="screen">
            div {
                margin-bottom: 20px;
            }
            .reset,
            .wasSent {
                font-weight: bold;
            }
            .paddingChunk {
                color: #999;
            }
            .links a {
                display: inline-block;
                padding: 20px 30px;
                text-decoration: none;
            }
            .links a:first-child,
            .links .reset {
                padding-left: 0;
            }
        </style>    
    </head>
    <body>
        
        <? if ($reset) { ?>
          <div class="reset">
            Resetting pages. Now starting with page 1.
          </div>  
        <? } ?>
        
        <? if ($wasSent) { ?>
          <div class="wasSent">
            This page was sent to <?=htmlentities($config['receiver'])?>.
          </div>  
        <? } ?>
        
        <h1>
            <?= $config['longTextFile']." ". ($currentPage+1) . "/" . $pagesLength?>            
        </h1>
        
        <div class="text">
            <span class="paddingChunk"><?=nl2br(htmlentities($paddingChunk))?></span><?=nl2br(htmlentities($chunk))?>
        </div>
        
        <div class="links">
            <a href="<?=$serverURL;?>?page=1" title="First Page">|<</a>
            <a href="<?=$serverURL;?>?page=<?=$previousPage + 1?>" title="Previous Page"><</a>  
            <a href="<?=$serverURL;?>?page=<?=$nextPage + 1?>" title="Next Page">></a>
            <a href="<?=$serverURL;?>?page=<?=$pagesLength?>" title="Last Page">>|</a> 
            <br>
            <a class="reset" href="<?=$serverURL;?>?reset" title="Reset sent pages">Reset</a> 
        </div>
    </body>
</html>

Später sah ich dann, dass Dripread genau das gleiche macht bzw. DailyLit-mit-eigenen-Texten ist :D

·
Mastodon