1:   2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19:  20:  21:  22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33:  34:  35:  36:  37:  38:  39:  40:  41:  42:  43:  44:  45:  46:  47:  48:  49:  50:  51:  52:  53:  54:  55:  56:  57:  58:  59:  60:  61:  62:  63:  64:  65:  66:  67:  68:  69:  70:  71:  72:  73:  74:  75:  76:  77:  78:  79:  80:  81:  82:  83:  84:  85:  86:  87:  88:  89:  90:  91:  92:  93:  94:  95:  96:  97:  98:  99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 
<?php

/**
 * Handles sound processing. In order to make sure the visual
 * verification is still accessible for all users, a sound clip is being addded
 * that reads the letters that are being shown.
 *
 * Simple Machines Forum (SMF)
 *
 * @package SMF
 * @author Simple Machines http://www.simplemachines.org
 * @copyright 2019 Simple Machines and individual contributors
 * @license http://www.simplemachines.org/about/smf/license.php BSD
 *
 * @version 2.1 RC1
 */

if (!defined('SMF'))
    die('No direct access...');

/**
 * Creates a wave file that spells the letters of $word.
 * Tries the user's language first, and defaults to english.
 * Used by VerificationCode() (Register.php).
 *
 * @param string $word
 * @return boolean false on failure
 */

function createWaveFile($word)
{
    global $settings, $user_info;

    // Allow max 2 requests per 20 seconds.
    if (($ip = cache_get_data('wave_file/' . $user_info['ip'], 20)) > 2 || ($ip2 = cache_get_data('wave_file/' . $user_info['ip2'], 20)) > 2)
        die(send_http_status(400));
    cache_put_data('wave_file/' . $user_info['ip'], $ip ? $ip + 1 : 1, 20);
    cache_put_data('wave_file/' . $user_info['ip2'], $ip2 ? $ip2 + 1 : 1, 20);

    // Fixate randomization for this word.
    $tmp = unpack('n', md5($word . session_id()));
    mt_srand(end($tmp));

    // Try to see if there's a sound font in the user's language.
    if (file_exists($settings['default_theme_dir'] . '/fonts/sound/a.' . $user_info['language'] . '.wav'))
        $sound_language = $user_info['language'];

    // English should be there.
    elseif (file_exists($settings['default_theme_dir'] . '/fonts/sound/a.english.wav'))
        $sound_language = 'english';

    // Guess not...
    else
        return false;

    // File names are in lower case so lets make sure that we are only using a lower case string
    $word = strtolower($word);

    // Loop through all letters of the word $word.
    $sound_word = '';
    for ($i = 0; $i < strlen($word); $i++)
    {
        $sound_letter = implode('', file($settings['default_theme_dir'] . '/fonts/sound/' . $word{$i} . '.' . $sound_language . '.wav'));
        if (strpos($sound_letter, 'data') === false)
            return false;

        $sound_letter = substr($sound_letter, strpos($sound_letter, 'data') + 8);
        switch ($word{$i} === 's' ? 0 : mt_rand(0, 2))
        {
            case 0 :
                for ($j = 0, $n = strlen($sound_letter); $j < $n; $j++)
                    for ($k = 0, $m = round(mt_rand(15, 25) / 10); $k < $m; $k++)
                        $sound_word .= $word{$i} === 's' ? $sound_letter{$j} : chr(mt_rand(max(ord($sound_letter{$j}) - 1, 0x00), min(ord($sound_letter{$j}) + 1, 0xFF)));
                break;

            case 1:
                for ($j = 0, $n = strlen($sound_letter) - 1; $j < $n; $j += 2)
                    $sound_word .= (mt_rand(0, 3) == 0 ? '' : $sound_letter{$j}) . (mt_rand(0, 3) === 0 ? $sound_letter{$j + 1} : $sound_letter{$j}) . (mt_rand(0, 3) === 0 ? $sound_letter{$j} : $sound_letter{$j + 1}) . $sound_letter{$j + 1} . (mt_rand(0, 3) == 0 ? $sound_letter{$j + 1} : '');
                $sound_word .= str_repeat($sound_letter{$n}, 2);
                break;

            case 2:
                $shift = 0;
                for ($j = 0, $n = strlen($sound_letter); $j < $n; $j++)
                {
                    if (mt_rand(0, 10) === 0)
                        $shift += mt_rand(-3, 3);
                    for ($k = 0, $m = round(mt_rand(15, 25) / 10); $k < $m; $k++)
                        $sound_word .= chr(min(max(ord($sound_letter{$j}) + $shift, 0x00), 0xFF));
                }
                break;
        }

        $sound_word .= str_repeat(chr(0x80), mt_rand(10000, 10500));
    }

    $data_size = strlen($sound_word);
    $file_size = $data_size + 0x24;
    $sample_rate = 16000;

    // Disable compression.
    ob_end_clean();
    header('content-encoding: none');

    // Output the wav.
    header('content-type: audio/x-wav');
    header('expires: ' . gmdate('D, d M Y H:i:s', time() + 525600 * 60) . ' GMT');
    header('content-length: ' . ($file_size + 0x08));

    echo pack('nnVnnnnnnnnVVnnnnV', 0x5249, 0x4646, $file_size, 0x5741, 0x5645, 0x666D, 0x7420, 0x1000, 0x0000, 0x0100, 0x0100, $sample_rate, $sample_rate, 0x0100, 0x0800, 0x6461, 0x7461, $data_size), $sound_word;

    // Noting more to add.
    die();
}

?>