Typecho在我用过的博客系统中我认为是最优秀的一个。虽然Typecho的设计初衷是针对个人用户,一般情况下完全能够满足个人用户的日常需求。但是博客作为一个开放的公众平台,难免会涉及到多用户的登录、注册等操作。

如果开放了用户系统,那么前台登录注册就显得有些必要了。然而百度了一遍之后,我完全没有找到合适的解决方案,多数文章都是照搬照抄,千篇一律的表示 <?php $this->$options->loginAction(); ?>

但是都无一例外的表示这种方法不能有效的提示用户,比如用户名或密码错误等信息。这个样子肯定是非常影响用户体验的。没办法,只能靠自己了。

先说一下我的思路。

Typecho的登录逻辑是将用户名和密码提交到一个叫 loginAction() 的方法中,然后判断是否登录成功。经过测试,用户初次注册登录成功后会跳转到 welcome.php,否则跳转到 profile.php,登录失败则提示错误信息,并不会发生跳转。管理员登录成功则会跳转到后台首页。

本着不修改源码的前提,我突然想到了 iframe

我们都知道 iframe 有一个 onload 方法,触发条件是当内容加载完成。所以我们可以通过监听 iframesrc 变化,来判断是否登录成功。

<form onsubmit="return check()">
    <input id="username" type="text" />
    <input id="password" type="password" />
    <button id="submit">提交</button>
</form>
function check() {
    //在这里可以做一些表单验证的操作,不做也完全可以,Typecho本身也会对用户名和密码的合法性做出判断。
    var iframe = document.createElement('iframe');
    iframe.src = '/admin/login.php';
    iframe.style.display = 'none';
    if(iframe.attachEvent){
        iframe.attachEvent('onload',function(){
            login(this)
        })
    } else {
        iframe.onload = function(){
            login(this)
        }
    }
    document.body.appendChild(iframe);
    return false; //阻止表单提交
}

function login(obj){
    var url = obj.contentWindow.location.href;
    if(url.indexOf('login.php') != -1){
        var message = obj.contentWindow.document.getElementsByClassName('error')[0];
        if(message){ //存在message表示有错误提示
            alert(message.innerText);
        } else { //自动登录,username和password自行获取
           obj.contentWindow.document.getElementById('name').value = username;
           obj.contentWindow.document.getElementById('password').value = password;
           obj.contentWindow.document.login.submit(); //提交表单
        }
    } else if(url.indexOf('profile.php') != -1 || url.indexOf('welcome.php' != -1)){ //普通用户登录成功
        window.location.reload();
    } else { //管理员登录成功
        window.location.href = '/admin/;
    }
}

经过测试,的确可以达到登录的目的。奈何我也不是专业人员,暂时也想不到其他方法,如果你有更好的解决方案,欢迎一起交流。