1

(9 replies, posted in Support)

Hey, much better now! :)
It throws the "No file upload detected ..." error.
Well done.

2

(9 replies, posted in Support)

This can lead to odd posts, where somebody comments on a nonexistent picture he meant to upload but was rejected.

3

(4 replies, posted in Support)

Could you give some help on how to implement such a feature h3? I'm a PHP newbie.

I think it would be best if the admin could set a certain amount of threads to be allowed in a category. When it is reached and a new thread is created the thread at the end of the board gets deleted. That should complement saging/aging nicely.

4

(0 replies, posted in Discuss)

This finds links marked with BBCode:

    // This finds http URLs in the form [url]http://www.google.com/page[/url]
    //$string = ereg_replace("\[url\](http:[^>\r\n]+)\[/url\]","${lt}a href=${q}\\1${q}${gt}\\1${lt}/a${gt}",$string);

The next one is better (imo) as it finds plain text Links. But it's either this or the BBCode one above.

    //This finds a plain text-url (http://www.google.com or www.google.com) and creates a link from it 
 
//"www."
   $pattern_preg1 = '#(^|\s)(www|WWW)\.([^\s<>\.]+)\.([^\s\n<>]+)#sm';
   $replace_preg1 = '\\1${lt}a href=${q}http://\\2.\\3.\\4${q} target=${q}_blank${q} class=${q}link${q}${gt}\\2.\\3.\\4${lt}/a${gt}';

//"http://"
   $pattern_preg2 = "#(^|[^\"=\]]{1})(http|HTTP|ftp)(s|S)?://([^\s<>\.]+)\.([^\s<>]+)#sm";
   $replace_preg2 = "\\1${lt}a href=${q}\\2\\3://\\4.\\5${q} target=${q}_blank${q} class=${q}link${q}${gt}\\2\\3://\\4.\\5${lt}/a${gt}";
  
   $string = preg_replace($pattern_preg1, $replace_preg1, $string);
   $string = preg_replace($pattern_preg2, $replace_preg2, $string);

Basic BulletinBoardCode:

 // This finds [b]BOLD TEXT[/b] [i]ITALIC TEXT[/i] [u]UNDERLINED TEXT[/u]
    $string = preg_replace("/\[(\/?)([biuq])\]/i", "${lt}$1$2${gt}", $string);

5

(9 replies, posted in Discuss)

Ah, I see. Seems to do nothing on windows.

6

(3 replies, posted in Support)

I tried it now, the thumbnail is just a white png.
The preview is created by ImageMagick?

7

(4 replies, posted in Support)

Oh, the dying threads (after a certain amount of posts) are a useful feature of imageboards. 
Is there another automatic way to prune old threads then?
Because without it on a busy forum your server will soon be stuffed.

8

(9 replies, posted in Support)

Sorry, my mistake. It's not related to the MB/KB.

Sometimes I get a warning:
"No file upload detected - please make sure your post wasn't empty and that you didn't exceed the maximum file size for upload (512000 bytes)"
That happens only if there was no comment in the post it seems.
If there was a comment it just posts that comment. And that was where I missed that warning. But it shouldn't post at all I think because obviously something went wrong and the outcome won't please a user who tried to upload. If he just wanted the text he could just post text after all.

9

(3 replies, posted in Support)

I tried uploading several PNGs (saved with different settings from photoshop) but none produced a preview in the threadview. The full picture was displayed fine. I'm on Firefox2.

10

(4 replies, posted in Support)

From conf.php:

define("FEATURE_SAGE",20);            // Number of replies before no longer bumped, or false

What happens when I set this to false, can it get bumped infinitely?
When does the thread die?

11

(9 replies, posted in Support)

I changed it to KB but now it doesn't realise when the image is to big anymore. It seems to try to upload the image then just makes the post without the image. No warning, no nothing. :/

Works with decimal fractions of MB though "0.5 MB" looks a bit silly. I want KB!

12

(9 replies, posted in Discuss)

I changed the code here so a tooltip notifies the user that he can change the captcha.

And I noticed that when hovering over "Post" in the menu it says: "Post a image (P)" It should be "Post an image" or "Post a message" (Since an image isn't required by default.) But what does the "(P)" mean? Maybe that's obvious for others but I don't get it.

13

(2 replies, posted in Support)

Thank you, I changed it to obfuscated form.
Regarding security with cookies: How about a "Remember me on this computer"-option in the preferences?

14

(9 replies, posted in Discuss)

h3 wrote:

Hmm, having a fixed number of characters greatly increases the machine-readability of captchas, whose sole purpose to defeat machine readability, so the idea seemed ill-advised to me at the time I was working on it.

Ah, I didn't know that. Well in that case I will just leave at that.

To exclude a few letters that might cause user mistakes I added in
includes/functions.php line 792:

$code = ereg_replace("[IJLOQ]","",$code);

But you mentioned noticing errors with that?

15

(2 replies, posted in Support)

Maybe I can just turn this on somewhere but I haven't seen it:
The tripcode always shows in clear text, which is great for social engineering but bad for security, especially when it's an admin.
The tripcode should show as: ***** instead.

16

(9 replies, posted in Discuss)

Thanks, works great.
To get a "hand"-cursor when pointing at the captcha I did this:
In templates/post.tmpl SEARCH:

<td><input type="text" id="verify" name="verify" size="10"/> <img src="verify?s={seed}" alt="verify" /></td>

REPLACE

<td><div id="verifier" alt="Click for a new captcha" title="Click for a new captcha"><input type="text" id="verify" name="verify" size="10"/> <img src="verify?s={seed}" alt="verify" /></div></td>

And in css/base.css ADD:

#verifier {cursor:pointer;}

EDIT: I edited this a bit to get a tooltip when hovering over the captcha saying: "Click for a new capcha".

One more thing: It would be nice if there was a consistent number of captcha letters. Preferably configurable. :)

17

(9 replies, posted in Discuss)

A new user won't know that numbers aren't used. ;)
SMF forum software has an optional captcha when registering where you can request a new captcha. You can see it here: http://www.strangebedfellows.de/index.p … n=register

Here's the code (sources/register.php)

    // Generate a visual verification code to make sure the user is no bot.
    $context['visual_verification'] = empty($modSettings['disable_visual_verification']);
    if ($context['visual_verification'])
    {
        $context['use_graphic_library'] = in_array('gd', get_loaded_extensions());
        $context['verificiation_image_href'] = $scripturl . '?action=verificationcode;rand=' . md5(rand());

        // Only generate a new code if one hasn't been set yet
        if (!isset($_SESSION['visual_verification_code']))
        {
            // Skip I, J, L, O and Q.
            $character_range = array_merge(range('A', 'H'), array('K', 'M', 'N', 'P'), range('R', 'Z'));

            // Generate a new code.
            $_SESSION['visual_verification_code'] = '';
            for ($i = 0; $i < 5; $i++)
                $_SESSION['visual_verification_code'] .= $character_range[array_rand($character_range)];
        }
    }
}

And the code from Sources/Subs-Graphics.

// Create the image for the visual verification code.
function showCodeImage($code)
{
    global $settings;

    // Is this GD2? Needed for pixel size.
    $testGD = get_extension_funcs('gd');
    $gd2 = in_array('imagecreatetruecolor', $testGD) && function_exists('imagecreatetruecolor');
    unset($testGD);

    // The amount of pixels inbetween characters.
    $character_spacing = 1;

    // The color of the characters shown (red, green, blue).
    $foreground_color = array(64, 101, 136);
    $background_color = array(236, 237, 243);

    // Has the theme author requested a custom color?
    if (isset($settings['verification_foreground'], $settings['verification_background']))
    {
        $foreground_color = $settings['verification_foreground'];
        $background_color = $settings['verification_background'];
    }

    if (!is_dir($settings['default_theme_dir'] . '/fonts'))
        return false;

    // Get a list of the available fonts.
    $font_dir = dir($settings['default_theme_dir'] . '/fonts');
    $font_list = array();
    $ttfont_list = array();
    while ($entry = $font_dir->read())
    {
        if (preg_match('~^(.+)\.gdf$~', $entry, $matches) === 1)
            $font_list[] = $entry;
        elseif (preg_match('~^(.+)\.ttf$~', $entry, $matches) === 1)
            $ttfont_list[] = $entry;
    }

    if (empty($font_list))
        return false;

    // Create a list of characters to be shown.
    $characters = array();
    $loaded_fonts = array();
    for ($i = 0; $i < strlen($code); $i++)
    {
        $characters[$i] = array(
            'id' => $code{$i},
            'font' => array_rand($font_list),
        );

        $loaded_fonts[$characters[$i]['font']] = null;
    }

    // Load all fonts and determine the maximum font height.
    foreach ($loaded_fonts as $font_index => $dummy)
        $loaded_fonts[$font_index] = imageloadfont($settings['default_theme_dir'] . '/fonts/' . $font_list[$font_index]);

    // Determine the dimensions of each character.
    $total_width = $character_spacing * strlen($code) + 10;
    $max_height = 0;
    foreach ($characters as $char_index => $character)
    {
        $characters[$char_index]['width'] = imagefontwidth($loaded_fonts[$character['font']]);
        $characters[$char_index]['height'] = imagefontheight($loaded_fonts[$character['font']]);

        $max_height = max($characters[$char_index]['height'], $max_height);
        $total_width += $characters[$char_index]['width'];
    }

    // Create an image.
    $code_image = imagecreate($total_width, $max_height);

    // Draw the background.
    $bg_color = imagecolorallocate($code_image, $background_color[0], $background_color[1], $background_color[2]);
    imagefilledrectangle($code_image, 0, 0, $total_width - 1, $max_height - 1, $bg_color);

    // Randomize the foreground color a little.
    for ($i = 0; $i < 3; $i++)
        $foreground_color[$i] = rand(max($foreground_color[$i] - 3, 0), min($foreground_color[$i] + 3, 255));
    $fg_color = imagecolorallocate($code_image, $foreground_color[0], $foreground_color[1], $foreground_color[2]);

    // Color for the dots.
    for ($i = 0; $i < 3; $i++)
        $dotbgcolor[$i] = $background_color[$i] < $foreground_color[$i] ? rand(0, max($foreground_color[$i] - 20, 0)) : rand(min($foreground_color[$i] + 20, 255), 255);
    $randomness_color = imagecolorallocate($code_image, $dotbgcolor[0], $dotbgcolor[1], $dotbgcolor[2]);

    // Fill in the characters.
    $cur_x = 0;
    foreach ($characters as $char_index => $character)
    {
        // Can we use true type fonts?
        $can_do_ttf = function_exists('imagettftext');
        if (!empty($can_do_ttf))
        {
            // GD2 handles font size differently.
            $font_size = $gd2 ? rand(15, 18) : rand(18, 25);

            // Work out the sizes - also fix the character width cause TTF not quite so wide!
            $font_x = $cur_x + 5;
            $font_y = $max_height - rand(2, 8);

            // What font face?
            if (!empty($ttfont_list))
            {
                $fontface = $settings['default_theme_dir'] . '/fonts/' . $ttfont_list[rand(0, count($ttfont_list) - 1)];
                //log_error($fontface);
            }

            // What color are we to do it in?
            $is_reverse = rand(0, 1);
            $char_color = imagecolorallocate($code_image, rand(max($foreground_color[0] - 2, 0), $foreground_color[0]), rand(max($foreground_color[1] - 2, 0), $foreground_color[1]), rand(max($foreground_color[2] - 2, 0), $foreground_color[2]));

            $angle = rand(-100, 100) / 10;
            $show_letter = rand(0, 1) ? $character['id'] : strtolower($character['id']);
            $fontcord = @imagettftext($code_image, 18, $angle, $font_x, $font_y, $char_color, $fontface, $show_letter);
            if (empty($fontcord))
                $can_do_ttf = false;
            elseif ($is_reverse)
            {
                imagefilledpolygon($code_image, $fontcord, 4, $fg_color);
                // Put the character back!
                imagettftext($code_image, 18, $angle, $font_x, $font_y, $randomness_color, $fontface, $show_letter);
            }

            if ($can_do_ttf)
                $cur_x = max($fontcord[2], $fontcord[4]) + 3;
        }

        if (!$can_do_ttf)
        {
            // Rotating the characters a little...
            if (function_exists('imagerotate'))
            {
                $char_image = function_exists('imagecreatetruecolor') ? imagecreatetruecolor($character['width'], $character['height']) : imagecreate($character['width'], $character['height']);
                $char_bgcolor = imagecolorallocate($char_image, $background_color[0], $background_color[1], $background_color[2]);
                imagefilledrectangle($char_image, 0, 0, $character['width'] - 1, $character['height'] - 1, $char_bgcolor);
                imagechar($char_image, $loaded_fonts[$character['font']], 0, 0, $character['id'], imagecolorallocate($char_image, rand(max($foreground_color[0] - 2, 0), $foreground_color[0]), rand(max($foreground_color[1] - 2, 0), $foreground_color[1]), rand(max($foreground_color[2] - 2, 0), $foreground_color[2])));
                $rotated_char = imagerotate($char_image, rand(-100, 100) / 10, $char_bgcolor);
                imagecopy($code_image, $rotated_char, $cur_x, 0, 0, 0, $character['width'], $character['height']);
                imagedestroy($rotated_char);
                imagedestroy($char_image);
            }
    
            // Sorry, no rotation available.
            else
                imagechar($code_image, $loaded_fonts[$character['font']], $cur_x, floor(($max_height - $character['height']) / 2), $character['id'], imagecolorallocate($code_image, rand(max($foreground_color[0] - 2, 0), $foreground_color[0]), rand(max($foreground_color[1] - 2, 0), $foreground_color[1]), rand(max($foreground_color[2] - 2, 0), $foreground_color[2])));
            $cur_x += $character['width'] + $character_spacing;
        }
    }

    // Make the background color transparent.
    imagecolortransparent($code_image, $bg_color);

    // Add some randomness to the background.
    for ($i = rand(0, 2); $i < $max_height; $i += rand(1, 2))
        for ($j = rand(0, 10); $j < $total_width; $j += rand(1, 15))
            imagesetpixel($code_image, $j, $i, rand(0, 1) ? $fg_color : $randomness_color);

    // Put in some lines too.
    $num_lines = 2;
    for ($i = 0; $i < $num_lines; $i++)
    {
        if (rand(0, 1))
        {
            $x1 = rand(0, $total_width);
            $x2 = rand(0, $total_width);
            $y1 = 0; $y2 = $max_height;
        }
        else
        {
            $y1 = rand(0, $max_height);
            $y2 = rand(0, $max_height);
            $x1 = 0; $x2 = $total_width;
        }

        imageline($code_image, $x1, $y1, $x2, $y2, rand (0, 1) ? $fg_color : $randomness_color);
    }

    // Show the image.
    if (function_exists('imagegif'))
    {
        header('Content-type: image/gif');
        imagegif($code_image);
    }
    else
    {
        header('Content-type: image/png');
        imagepng($code_image);
    }

    // Bail out.
    imagedestroy($code_image);
    die();
}

// Create a letter for the visual verification code.
function showLetterImage($letter)
{
    global $settings;

    if (!is_dir($settings['default_theme_dir'] . '/fonts'))
        return false;

    // Get a list of the available font directories.
    $font_dir = dir($settings['default_theme_dir'] . '/fonts');
    $font_list = array();
    while ($entry = $font_dir->read())
        if ($entry{0} !== '.' && is_dir($settings['default_theme_dir'] . '/fonts/' . $entry) && file_exists($settings['default_theme_dir'] . '/fonts/' . $entry . '.gdf'))
            $font_list[] = $entry;

    if (empty($font_list))
        return false;

    // Pick a random font.
    $random_font = $font_list[array_rand($font_list)];

    // Check if the given letter exists.
    if (!file_exists($settings['default_theme_dir'] . '/fonts/' . $random_font . '/' . $letter . '.gif'))
        return false;

    // Include it!
    header('Content-type: image/gif');
    include($settings['default_theme_dir'] . '/fonts/' . $random_font . '/' . $letter . '.gif');

This should be it.

18

(9 replies, posted in Support)

Thank you. I'll try this out.

EDIT: Yeap, works good. I also changed templates/post.tmpl to read KB now.



Something I just noticed:
In the Readme it says:
   /mods
           Moderator features are available here: managing bans. To access ...

While the real adress is /mod
Didn't want to make a new thread for this.

19

(9 replies, posted in Discuss)

It would be nice if there was a way to do it.
Reloading the page isn't that great because it empties the form.

Speaking of the captcha, the "O" looks like a zero and can therefor lead to errors.
Similarly the letter "Q" is hard to tell from "O" (the little line could be captcha interferences).
Maybe these letters could just be removed from captcha generation.

20

(9 replies, posted in Support)

When I set in conf.php
define("MAXIMUM_SIZE",500000);        // bytes
it shows the file size as 0 MB on the board.

How can I show it either as 0.5MB or in KB?

Okay, I got it. In includes/post.php:

SEARCH
   if($_POST["name"]) {
       $name = $_POST["name"];
       setcookie("name",$_POST["name"],COOKIE_EXPIRES);
   } else {
       array_push($errors,$ERRORS["namerequired"]);
   }

REPLACE
    $name = $_POST["name"] ? name($_POST["name"]) : "Anonymous";
    setcookie("name",$_POST["name"],COOKIE_EXPIRES);


Also the changes in js/ochiba.js as described by hr above.

I have taken this code from the tripcode and it works but it would be even more elegant if there was a check, whether a cookie_name exists before posting, and if there is none:
setcookie("name","Anonymous",COOKIE_EXPIRES);
So that when one has never posted on the board before, the name is filled in with "Anonymous" by default.

EDIT: Next step might be to use a variable instead of "Anonymous" which by default is empty and throws the name-required-error. Once set in conf.php it uses whatever the Admin specified and throws no error anymore. Well, just thinking here. :)

Oh hey thank you for your help!

2. Okay, I commented out that javascript and in includes/post.php I put this line after "// Name is required" :
$_POST["name"] = $_POST["name"]=="" ? $_POST["name"] : "Anonymous";

Now after posting I get a screen saying:
"The following error(s) occurred
A name is required
"
The post isn't made.

3. Thanks, works fine. :)

Okay, I found the old support forum.
1. It seems there is no normal way of deleting categories. Correct me if I'm wrong.
2. Someone mentioned to insert this line:
$_POST["name"] = $_POST["name"]=="" ? $_POST["name"] : "Anonymous";
but the place where to add it seems to have changed. I tried putting it after the comment:
// Name is required
But to no avail. Well even if it worked the Name-line would still be red...mmh.
I'm thinking it would be nice if the input for name would just be "Anyonymous" by default.

So I tried this: In templates/post.tmpl
SEARCH
    <th class="required">Name:</th>
    <td><input id="name" type="text" name="name" value="{cookie_name}"/></td>
REPLACE
    <th>Name:</th>
    <td><input id="name" type="text" name="name" value="Anonymous"/></td>

This works just fine, the drawback being that if someone filled in their name it won't be remembered anymore. Maybe someone has an idea on how we could have our pie and eat it too? What I mean is: "Anonymous" by default and "{cookie_name}" if it was filled in before.

3. Still no idea

First of all thanks for ochiba! I like it! :)
Now to my questions:

1. How can I delete categories short of deleting them in the database?
2. How can I set the name in posts to not be required (use "Anonymous" instead)?
EDIT: 3. How do I set the standard CSS?