微擎:小程序上传图片重定向问题

调用wx.uploadFile总是返回如下代码

<!DOCTYPE html>
<html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
    </head>
    <body>
        <script type="text/javascript">
            var ua = navigator.userAgent.toLowerCase();
            var isWeixin = ua.indexOf('micromessenger') != -1;
            var isAndroid = ua.indexOf('android') != -1;
            var isIos = (ua.indexOf('iphone') != -1) || (ua.indexOf('ipad') != -1);
            if (!isWeixin) {
                document.head.innerHTML = '<title>抱歉,出错了</title><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0"><link rel="stylesheet" type="text/css" href="https://res.wx.qq.com/open/libs/weui/0.4.1/weui.css">';
                document.body.innerHTML = '<div class="weui_msg"><div class="weui_icon_area"><i class="weui_icon_info weui_icon_msg"></i></div><div class="weui_text_area"><h4 class="weui_msg_title">请在微信客户端打开链接</h4></div></div>';
            }
        </script>
    </body>
</html>

百思不得其解,上网查询也是无果,没有办法只能看下HTTP请求包。

微信截图_20190523173447.png可以看到被302重定向了,后端上传代码里并没有重定向操作,所以查看了下标识,发现MicroMessenger。猜测应该是被微擎重定向了。

微擎源代码里有这么一段:

// 检查是否在微信中打开
public static function isMicroMessage($agent = '')
{
    $agent = self::getAgent($agent);
    if (stripos($agent, 'MicroMessenger') !== false) {
        return self::MICRO_MESSAGE_YES;
    } else {
    return self::MICRO_MESSAGE_NOT;
    }
}

会检查你的agent,如果包含MicroMessenger则会当成是在微信中打开。然后调用getOauthCodeUrl|getOauthCodeUrl去获取你的微信信息。所以会造成重定向。

修改微信开发者工具,将请求头改掉

333.png然后上传成功

微信截图_20190523173600.png

真实的环境下,一般会存在第三方存储服务商,所以不会发生这种情况。如果你要在微擎里改掉授权操作,那么很有可能出现一系列问题,所以还是建议在微擎外写一个上传接口。

微信小程序未授权与授权后关联问题的解决

微信小程序有一个授权登录,在你没有授权的时候,一般会限制访问,实际完全可以避免这种情况。观看了一些app或者应用的处理上发现了一些规律。都存在一个唯一的临时用户。

这个临时用户是体现给前端展示的,一般是一个随机名字,或者一组规律的字串。这有一个好处,当你微信小程序授权以后可以拿到这一个临时的字符串,然后与你的授权信息去做匹配。app的道理等同。


微信小程序的相关文档

屏幕快照 2019-05-18 下午11.25.53.png

清理策略里有写,只有在代码包被清理的时候本地缓存才会清理。也就是说,除去代码清理以外,你完全可以使用这几个函数来做本地的临时用户存储。

__autoload 内部实现原理

__autoload  

官方:尝试加载未定义的类。我的理解是在New 对象的时候,会将对象名传递。

<?php
function __autoload($class_name) { 
    echo '加载的类名:'.$class_name;
} 

@$a = new iwonmo(); 
@$a = new iwonmo1();

运行结果输出:加载的类名:iwonmo

当New的类不存在时,可以通过这个函数进行include/require。

不过注意官方的警告:This feature has been DEPRECATED as of PHP 7.2.0. Relying on this feature is highly discouraged. 在7.2.0以后的版本被弃用

SPL

SPL的全称是:Standard PHP Library (PHP标准库),版本:PHP 5 >= 5.1.0, PHP 7,这个库是做什么用的,在官网也有解释,只不过需要看英文版,因为中文版的介绍实际是不全的,不单单是这个解释。所以看PHP的文档尽量看英文版的。

The Standard PHP Library (SPL) is a collection of interfaces and classes that are meant to solve common problems.

No external libraries are needed to build this extension and it is available and compiled by default in PHP 5.0.0.

SPL provides a set of standard datastructure, a set of iterators to traverse over objects, a set of interfaces, a set of standard Exceptions, a number of classes to work with files and it provides a set of functions like spl_autoload_register()


大致的意思是SPL是一个解决常见问题接口或者的集合。然后里面提供了一组叫做SPL的函数。另外(英文里不包含):SPL函数也取代了__autoload。

spl_autoload_register的官方解释里有这么一句话:如果在你的程序中已经实现了__autoload()函数,它必须显式注册(explicitly registered )到__autoload()队列中。因为 spl_autoload_register()函数会将Zend Engine中的__autoload()函数取代为spl_autoload()或spl_autoload_call()。

对于这组函数可以翻阅PHP的源代码(php_spl.c):

int spl_autoload(const char *class_name, const char * lc_name, int class_name_len, const char * file_extension TSRMLS_DC) /* {{{ */
{
    char *class_file;
    int class_file_len;
    int dummy = 1;
    zend_file_handle file_handle;
    zend_op_array *new_op_array;
    zval *result = NULL;

    class_file_len = spprintf(&class_file, 0, "%s%s", lc_name, file_extension);

    if (zend_stream_open(class_file, &file_handle TSRMLS_CC) == SUCCESS) {
        if (!file_handle.opened_path) {
            file_handle.opened_path = estrndup(class_file, class_file_len);
        }
        if (zend_hash_add(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1, (void *)&dummy, sizeof(int), NULL)==SUCCESS) {
            new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC);
            zend_destroy_file_handle(&file_handle TSRMLS_CC);
        } else {
            new_op_array = NULL;
            zend_file_handle_dtor(&file_handle);
        }
        if (new_op_array) {
            EG(return_value_ptr_ptr) = &result;
            EG(active_op_array) = new_op_array;
    
            zend_execute(new_op_array TSRMLS_CC);
    
            destroy_op_array(new_op_array TSRMLS_CC);
            efree(new_op_array);
            if (!EG(exception)) {
                if (EG(return_value_ptr_ptr)) {
                    zval_ptr_dtor(EG(return_value_ptr_ptr));
                }
            }

            efree(class_file);
            return zend_hash_exists(EG(class_table), (char*)lc_name, class_name_len+1);
        }
    }
    efree(class_file);
    return 0;
} /* }}} */

大致就是找到这个文件,然后编译成OP代码,然后执行,释放。实际这个过程也是__autoload的过程。这里有一个地方是会将对象名转换为小写,不知道这段代码的意义。不过明白大致意思就可以。file_extension由于被宏定义,所以这里它是一个上下文。


个人理解,如有错误还望指出。

七牛 大文件上传

大文件报错:invalid multipart format: multipart: message too large

UploadManager->put 改为 UploadManager->putFile