<?php
// ----- 広く，Moodle多言語化に向けて役に立ちそうな関数 ----- //
// ブラウザに合わせてダウンロードファイル名のフォーマットを変更する
function convert_download_filename_encoding($filename) {
    if (check_browser_version('MSIE')) {
        if (strlen(rawurlencode($filename)) > 21 * 3 * 3) {
            $filename = mb_convert_encoding($filename, "SJIS-WIN", "UTF-8");
            $filename = str_replace('#', '%23', $filename);
        } else {
//          $filename = rawurlencode($filename);
            $filename = fs_rawurlencode($filename);
        }
    } else if (check_browser_version('Safari')) {
        $filename = "";
    }
    return $filename;
}

// クライアントＯＳの種類がiPodかどうかを調べる
function cliant_is_ipod() {
    if (!empty($_SERVER['HTTP_USER_AGENT'])) {
        if (strpos($_SERVER['HTTP_USER_AGENT'], 'iPod')) return true;
        if (strpos($_SERVER['HTTP_USER_AGENT'], 'iPhone')) return true;
    }
    return false;
}

// クライアントＯＳの種類がPSPかどうかを調べる
function cliant_is_psp() {
    if (!empty($_SERVER['HTTP_USER_AGENT'])) {
        if (strpos($_SERVER['HTTP_USER_AGENT'], 'PSP')) return true;
    }
    return false;
}

// サーバＯＳの種類がWindowsであるかどうかを調べる
function ostype_is_windows() {
    global $CFG;
    if (isset($CFG->ostype)) {
        if ($CFG->ostype != 'WINDOWS') return false;
        return true;
    } else {
/// lib/setup.phpより．
/// Calculate and set $CFG->ostype to be used everywhere. Possible values are:
/// - WINDOWS: for any Windows flavour.
/// - UNIX: for the rest
/// Also, $CFG->os can continue being used if more specialization is required
        if (stristr(PHP_OS, 'win') && !stristr(PHP_OS, 'darwin')) return true;
        return false;
    }
}

// UTF-8以外の文字コードに対応したrawurlencode
function byte_rawurlencode($str)
{
    $enc_str = mb_detect_encoding($str);
    $hexString = '';
    for ($i = 0; $i < mb_strwidth($str, $enc_str); $i++) {
        $c = mb_substr($str, $i, 1, $enc_str);
        if (strlen($c) <= 1) {
            $hexString .= $c;
        } else {
            for ($j = 0; $j < strlen($c); $j++) {
                $hexString .= '%'.sprintf("%02X", ord(substr($c, $j, 1)));
            }
        }
    }
    return $hexString;
}

// バックスラッシュはエンコードしないrawurlencode(): (2008/04/16)
function fs_rawurlencode($path)
{
//  $parts = explode('/', $path);
    $parts = mb_split('/', $path);  // シフトJISにも対応
//  $parts = array_map('rawurlencode', $parts);
    $parts = array_map('byte_rawurlencode', $parts);
    $path  = implode('/', $parts);
    return $path;
}

// 擬似的RAWURL：コロン，半角スペース，スラッシュ，バックスラッシュはエンコードしない．
// ドライブレターを含むようなファイルシステム寄りの場合にのみ使用する．それ以外はfs_rawurlencode()を使用．
// 当初考えたfs_rawurlencode()だったが，効率が悪いコードなので特殊な場合以外は使用しないこととした(2008/04/16)
// 合わせて，関数名をfs_rawurlencode()からspecial_rawurlencode()に変更．
// ファイルシステムの文字コードに擬似RAWURLを用いる場合以外は考えられない．
function special_rawurlencode($path)
{
    $path = trim($path, " ");
    $ret = "";
    // "\\"で分割
    $path_parts = mb_split("\\\\", $path);
    foreach ($path_parts as $key_sl1 => $path_slash1) {
        // "/" で分割
        $ret_slash2 = "";
        $path_slash1 = mb_split("/", $path_slash1);
        foreach ($path_slash1 as $key_sl2 => $path_slash2) {
            // "." で分割
            $ret_dot = "";
            $path_slash2 = mb_split("\.", $path_slash2);
            foreach ($path_slash2 as $key_dot => $path_dot) {
                // ":" で分割
                $ret_col = "";
                $path_dot = mb_split(":", $path_dot);
                foreach ($path_dot as $key_col => $path_col) {
                    // " " で分割
                    $ret_spc = "";
                    $path_col = mb_split(" ", $path_col);
                    foreach ($path_col as $key_spc => $path_spc) {
                        if ($key_spc == 0) $ret_spc = rawurlencode($path_spc);
                          else             $ret_spc .= ' ' . rawurlencode($path_spc);
                    }
                    if ($key_col == 0) $ret_col =$ret_spc;
                      else             $ret_col .= ':' . $ret_spc;
                }
                if ($key_dot == 0) $ret_dot = $ret_col;
                  else             $ret_dot .= '.' . $ret_col;
            }
            if ($key_sl2 == 0) $ret_sl2  = $ret_dot;
              else             $ret_sl2 .= '/' . $ret_dot;
        }
        if ($key_sl1 == 0) $ret = $ret_sl2;
          else             $ret .= '\\' . $ret_sl2;
    }
    return $ret;
}

// ----------------------------------------------
// pathinfo(), basename(), dirname()など，実装によって正しく機能しない場合のための代替関数．
// ユーザの判断で使用するか否かを判断して下さい．使用しない場合は，moodle/fsconfig.phpの
// $fsCFG->USEfsPathinfo=falseとして下さい．
//
// pathinfoがWindows版では正しく動作しないようである．例:"１.zip"
// オリジナルのpathinfo()に仕様を合わせようと思ったが，シングルバイトでも謎の挙動...
// 参照：http://moodle.org/mod/forum/discuss.php?d=73428
// この問題はLinux上のPHPでも発生する．zip書庫作成の際にzip書庫名に日本語が使えないといった
// 現象として顕在化する．したがって，問題が無い限り$fsCFG->USEfsPathinfo=trueとすることを勧めます．
// 以下，独自の仕様．
// 末尾が/で終わるパスの場合はdirnameのみ．basenameとextensionは""
// 拡張子が無い場合は，当然ながら最後の一つをbasenameとする．
// (1) pathinfo(str)
function fs_pathinfo($str)
{
    global $fsCFG;
    if (empty($fsCFG->USEfsPathinfo)) {
        return pathinfo(cleardoubleslashes($str));
    }

    $str = preg_replace('/(\/|\\\){1,}/','/',$str);
    $path_parts['dirname'] = $path_parts['basename'] = $path_parts['extension'] = '';
    $parts = mb_split("/", $str);
    $cnt = count($parts);
    for ($i = 0; $i < $cnt - 1; $i++) {
        if ($i == 0) $path_parts['dirname'] = $parts[0];
            else     $path_parts['dirname'] .= '/' . $parts[$i];
    }
    $path_parts['basename'] = $parts[$cnt - 1];
    $parts = mb_split("\.", $path_parts['basename']);
    $cnt = count($parts);
    if ($cnt == 1) $path_parts['extension'] = "";
       else        $path_parts['extension'] = $parts[$cnt - 1];
    return $path_parts;
}

// Windows版のbasename()はマルチバイト時の動作が怪しい．
// 以下の修正版を使用すると正常動作することが何度かあった．
// 他ＯＳ版のPHPの実装もマルチバイトに対応しているのかどうか，確認が取れていない．
// $suffixを追加 (2008/08/01)
// (2) basename(str)
function fs_basename($path, $suffix = NULL)
{
    global $fsCFG;
    if (empty($fsCFG->USEfsPathinfo)) {
        if ($suffix !== NULL)   return basename($path, $suffix);
            else                return basename($path);
    }
    $path_parts = fs_pathinfo($path);
    $bname = $path_parts['basename'];
    if ($suffix === NULL) return $bname;
    // 拡張子の'.'の付け忘れチェック（basename()との互換性を重視するならば以下の行はコメントアウト）
    if (mb_substr($suffix, 0, 1) !== '.') $suffix = '.'.$suffix;
    if (($pos = mb_strrpos($bname, $suffix)) === false) return $bname;
    $bname = mb_substr($bname, 0, $pos);
    return $bname;
}

// Windows版のdirname()は異常動作を確認していないが，実は同じ状況なのではないか？
// 他ＯＳ版のPHPの実装もマルチバイトに対応しているのかどうか，確認が取れていない．
// (3) dirname(str)
function fs_dirname($path)
{
    global $fsCFG;
    if (empty($fsCFG->USEfsPathinfo)) {
        return dirname($path);
    }
    $path_parts = fs_pathinfo($path);
    return $path_parts['dirname'];
}

/**
 * マルチバイト対応 str_replace
 * 
 * @version     Release 2
 * @author      HiNa (hina@bouhime.com)
 * @copyright   Copyright (C) 2006-2007 by HiNa(hina@bouhime.com).
 */

if(! function_exists('mb_str_replace')) {
    /**
     * マルチバイト対応 str_replace
     * 
     * @param   mixed   $search     検索文字列
     * @param   mixed   $replace    置換文字列
     * @param   mixed   $subject    対象文字列
     * @param   string  $encoding   文字列のエンコーディング(省略: 内部エンコーディング)
     *
     * @return  mixed   subject 内の search を replace で置き換えた文字列
     *
     * @note    この関数は配列に対応(search, replace, subject)しています。
     */
    function mb_str_replace($search, $replace, $subject, $encoding = 'auto') {
        if(! is_array($search)) {
            $search = array($search);
        }
        if(! is_array($replace)) {
            $replace = array($replace);
        }
        if(strtolower($encoding) === 'auto') {
            $encoding = mb_internal_encoding();
        }
        if(is_array($subject)) {
            $result = array();
            foreach($subject as $key => $val) {
                $result[$key] = mb_str_replace($search, $replace, $val, $encoding);
            }
            return $result;
        }
        
        $currentpos = 0;
        while(true) {
            $index = -1;
            $minpos = -1;
            foreach($search as $key => $find) {
                if($find == '') {
                    continue;
                }
                $findpos = mb_strpos($subject, $find, $currentpos, $encoding);
                if($findpos !== false) {
                    if($minpos < 0 || $findpos < $minpos) {
                        $minpos = $findpos;
                        $index = $key;
                    }
                }
            }
            if($minpos < 0) {
                break;
            }
            
            $r = array_key_exists($index, $replace) ? $replace[$index] : '';
            $subject = sprintf('%s%s%s',
                                    mb_substr($subject, 0, $minpos, $encoding),
                                    $r,
                                    mb_substr(
                                        $subject,
                                        $minpos + mb_strlen($search[$index], $encoding),
                                        mb_strlen($subject, $encoding),
                                        $encoding
                                    )
                                );
            $currentpos = $minpos + mb_strlen($r, $encoding);
        }
        return $subject;
    }
}

// MIMETYPEを追加するための関数
function append_mime($extension, $type, $icon = false)
{
    global $fsCFG;

    if (!empty($fsCFG->mimes)) $fsCFG->mimes = get_mimetypes_array();
}

// (Shirai107): 一行が998byteを超えるマルチバイト文字列を含む文章をメール送信すると強制改行により文字化けする問題 (2008/12/18)
// 再帰呼び出しのサブルーチン： function autocut998()より呼び出される
// $line : UTF-8
// $encode   : メール送信時に文字コード　ex) 'ISO-2022-JP'
function autocut998_sub($line, $max_line_length, $encode)
{
    if (($linelength = mb_strwidth($line)) == 0) return '';
    if (strlen(mb_convert_encoding($line, $encode, 'UTF-8')) <= $max_line_length) return $line;
    $offsetA = 0; $offsetB = $linelength;
    while (1) {
        $offsetC = (int)(($offsetA + $offsetB) / 2);
        if (($offsetC == $offsetA) || ($offsetC == $offsetB)) {
            $line = mb_substr($line, 0, $offsetC)."\n".autocut998_sub(mb_substr($line, $offsetC), $max_line_length, $encode);
            return $line;
        }
        $newlinelength = strlen(mb_convert_encoding(mb_substr($line, 0, $offsetC), $encode, 'UTF-8'));
        if ($newlinelength >= $max_line_length) $offsetB = $offsetC;
            else                                $offsetA = $offsetC;
    }
}
// こちらが呼び出し元
// $msg_data : UTF-8
// $encode   : メール送信時に文字コード　ex) 'ISO-2022-JP'
function autocut998($msg_data, $encode)
{
    $max_line_length = 998; # used below; set here for ease in change
    $max_line_length -= 8;  // 自信が無いので安全のために

    # normalize the line breaks so we know the explode works
    $msg_data = str_replace("\r\n","\n",$msg_data);
    $msg_data = str_replace("\r","\n",$msg_data);
    $lines = explode("\n",$msg_data);
    foreach ($lines as $pos=>$line) {
        if (strlen(mb_convert_encoding($line, $encode, 'UTF-8')) > $max_line_length) {
            $lines[$pos] = autocut998_sub($line, $max_line_length, $encode);
        }
    }
    $msg_data = implode("\n", $lines);
    return $msg_data;
}

// FORMのINPUTの属性に携帯電話用の属性（istyle, mode）を追加する
// http://kawama.jp/archives/2006/03/html.html
function keitai_alphabet4input()
{
    if (fs_function_enable('FS_DISABLE_KEITAIHANKAKUINPUT')) return ' istyle="3" mode="alphabet"';
}

?>