Web
Web

七牛 大文件上传

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

UploadManager->put 改为 UploadManager->putFile


原生与WebView传递超大文件

方法一

原生实现 分块读取接口,由JS去调用,读取本地文件。

方法二

将大文件转成特定格式如base64,以对象形式存储生成JS文件,动态加载JS文件,调用相应接口,获取base64数据。

js文件如下

function load(){
    var ob = new Object(); /** 这里内部会创建一个Handle<JSOBJECT>的对象 是一个地址 */
    ob.data="亿万数据"; /** 由于是内存地址所以可以存储小于当前内存的一块空间,理论上无限大 */
    return ob; /** 返回这一个对象 */
}

原生可以将文件base64写入到手机,然后webview的JS通过动态加载JS获取load函数,从而调用load函数实现得到大文件的数据。

调用方法(jQuery)

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <button style="width:100px;height:30px;" onclick="getJs()">获取</button>
    <script>
        function getJs(){
            $.getScript("hotLoad.js",(e)=>{
                console.log(load());
            });
        };
    </script>
</body>
</html>

由于getScript是Ajax实现的,所以注意跨域问题。使用其他方式实现JS的加载也可。

微信小程序附近人

代码很简单,需要前端不断的传入经纬度并且更新数据库用户表里的经纬度字段,然后重数据表中提取所有用户信息,在获取自身的经纬度,进行排序就可以了。

<?php
//自己的经纬度,对方的经纬度 ,返回单位 米 
function getdistance($lng1, $lat1, $lng2, $lat2) {
    $radLat1 = deg2rad($lat1);
    $radLat2 = deg2rad($lat2);
    $radLng1 = deg2rad($lng1);
    $radLng2 = deg2rad($lng2);
    $a = $radLat1 - $radLat2;
    $b = $radLng1 - $radLng2;
    $s = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2))) * 6370.996 * 1000;
    return $s;
}
//模拟数据库查找出的数据  j:经度 w:纬度
$array=[]; 
array_push($array,[
'j'=>36.6675927719,
'w'=>98.4400749207,
's'=>1
]);
array_push($array,[
'j'=>36.6708284639,
'w'=>98.4741497040,
's'=>2
]);
array_push($array,[
'j'=>36.6711038356,
'w'=>98.4590435028,
's'=>3
]);
//自己的经纬度
$j=36.6684189189;
$w=98.4375000000;
//上述数组正确的顺序 s: 1 3 2
function s($j,$w,&$array){
$len=count($array);
    for($i=1;$i<$len; $i++) {
        $tmp = $array[$i];
        for($j=$i-1;$j>=0;$j--) {
            if(getdistance($j,$w,$tmp['j'],$tmp['w'])<getdistance($j,$w,$array[$j]['j'],$array[$j]['w'])) {
                $array[$j+1] = $array[$j];
                $array[$j] = $tmp;
            } else {
                break;
            }
        }
    }
    return $array;
}
var_dump(s($j,$w,$array));


微信开发者工具插件开发

前天看了下HBuilder发现用它开发的微信小程序,在调试的时候可以直接进行微信开发者工具展示,觉得这个功能挺有意思,随机看了下微信开发者工具的文档,发现它提供了两种与微信开发者工具沟通的方法。

1、CLI

2、HTTP

文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/cli.html

不过并没有提供微信开发者工具公众号开发的一些“接口”,比如说刷新。如果说使用PhpStorm开发公众号,PhpStorm保存后,微信开发者工具可以自动刷新,那么是非常有意思的事情,所以我决定去实现它。

首先要明白微信开发者工具是用什么软件进行开发的,才能决定使用哪种方式进行插件开发。

一波三折后,你会发现这款工具是使用的nw.js开发的,https://nwjs.io/

1、阅读nw.js的文档,你会发现在编译的时候总会有一个叫做package.nw的文件夹,但是我在微信开发者工具的根目录并没有发现这个文件夹。这个思路又断了,

2、然后开始查看微信开发者工具,你会发现菜单上就有一个刷新的按钮,并且它存在快捷键,随即考虑另一种方案,发送组合键,这是win下的一种编程方式,在win中,界面是一种庞大的消息结构,是否可以尝试发送CTRL+V这种快捷键消息来进行操作,在真实的操作过程中发现存在一个问题,我的scancode每次发送后总是显示114,而真实的应该是18。后来认为是CTRL是系统键,微信开发者工具响应的模式不一样。如果你用osk进行屏幕键盘操作,你会发现是可以的,但是这种方法是无法准确的投递到窗口,因为需要WM_ACTIVE是你的开发者工具窗口,然后才能发送按键,这个时候scancode就是18。这种方法感觉不好,因为phpstorm保存后在激活开发者工具 ,然后在投递,整个展示的过程是不友好的。

3、后来决定换种思路,直接替换掉微信开发者工具的菜单,然后把click事件进行一个绑定拦截,但是在我动态调试的时候,没有拦截到菜单对应的几个api。而后重载的时候又发现老是出现nw.js框架的界面。昨晚调试的,由于太晚就没有按照这个思路折腾下去,因为这种的话,你要实现一个外部代码动态插入到微信开发者工具中,是很繁琐的一个步骤,并且不会保证软件的稳定性。

4、在菜单当中发现了一个叫做调试微信开发者工具的功能,在整个html的最底部有一个index.js的文件,这个可是一个新大陆,js代码如下:

const path = require('path')
const tools = require('../js/84b183688a46c9e2626d3e6f83365e13.js')
const locales = require('../js/common/locales/index.js')
const isMac = (process.platform === 'darwin')
const query = tools.getQuery(location.search)
// 记录工具开始运行的时间
global.beginTime = Date.now()
function hack() {
  // to prevent drag image or html
  document.body.addEventListener('dragover', function (e) {
    e.preventDefault()
    e.stopPropagation()
  }, false)
  document.body.addEventListener('drop', function (e) {
    e.preventDefault()
    e.stopPropagation()
  }, false)
  // 禁用滚轮缩放
  document.addEventListener('mousewheel', (event) => {
    if (event.ctrlKey) event.preventDefault()
  })
}
function initGlobal() {
  global.appVersion = nw.App.manifest.version
  global.useChromeRemoteDebugProtocal = false
  // mac 从application 启动时带的环境变量里没有 :/usr/local/bin
  isMac && (process.env.PATH += ':/usr/local/bin')
  // 在非 new instance 的窗口内可以共享
  global.shareData = {}
  global.appConfig = tools.getAppConfig()
  // global.appConfig.isDev = false
  // global.appConfig.isGamma = true
  // nw & foreground variables
  const Win = nw.Window.get()
  global.Win = Win
  global.contentDocument = document
  global.contentDocumentBody = document.body
  global.contentWindow = window
  global.windowMap = new Map()
  global.windowMap.set('LOGIN', global.Win)
  // worker 懒加载
  global.worker = {}
  Object.defineProperties(global.worker, {
    bbsLogWorker: {
      get() {
        if (!this._bbsLogWoker) {
          this._bbsLogWoker = new Worker('../js/2bc74df4df155a7d0d1c4df1e947d57d.js')
        }
        return this._bbsLogWoker
      },
    },
  })
  // 提供一个全局 reload 的方法
  global.reload = () => {
    for (key in require.cache) {
      require.cache[key] = undefined
    }
    location.reload()
  }
  global.devInfo = {}
  if (location.search) {
    global.isDevWindow = true
    global.devType = location.search.match(/devtype=(.*?)(&|$)/)[1]
    switch (global.devType) {
      case 'webdebugger': {
        global.devInfo.id = query.devid
        break
      }
      default: {
        global.devInfo.id = query.devid
        global.devInfo.appid = query.appid
        global.devInfo.projectname = query.projectname
        global.devInfo.projectpath = query.projectpath
        global.devInfo.projectid = `${global.devInfo.appid}_${encodeURIComponent(global.devInfo.projectname)}`
        global.devInfo.isTemp = Boolean(query.isTemp)
        global.devInfo.isOnline = Boolean(query.isOnline)
        if (global.devInfo.isTemp) {
          const tempLocalStorageKey = `temp_${global.devInfo.appid}_${global.devInfo.projectname}`
          global.devInfo.project = JSON.parse(localStorage[tempLocalStorageKey])
          delete localStorage[tempLocalStorageKey]
        }
      }
    }
    if (query.simple) {
      // 多账号模式登录
      global.isSimple = true
      global.userInfo = {
        openid: query.openid,
        nickName: query.nickName,
        headUrl: query.headUrl,
        contry: query.contry,
        city: query.city,
        loginStatus: query.loginStatus,
        province: query.province,
        sex: query.sex,
        newticket: query.newticket,
        ticketExpiredTime: parseInt(query.ticketExpiredTime),
        signature: query.signature,
        signatureExpiredTime: parseInt(query.signatureExpiredTime)
      }
    }
  }
  // parse cli
  global.CLI = {}
  try {
    global.CLI.isTestMode = nw.App.argv.indexOf('--test-mode') > -1
    global.autoTest = global.CLI.isTestMode
    if (nw.App.argv.indexOf('--only-simulator') > -1) {
      global.onlySimulator = true
    }
    if (nw.App.argv.indexOf('--online') > -1) {
      global.online = true
    }
    if (global.CLI.isTestMode) {
      const ind = nw.App.argv.indexOf('--id')
      if (ind > -1) {
        const raw = nw.App.argv[ind + 1]
        if (raw) {
          global.CLI.id = raw
        }
      }
    }
  } catch (err) {}
}
function initMenu() {
  // init initial menu in case of failure
  try {
    if (global.isDevWindow || isMac) {
      const menu = new nw.Menu({type: 'menubar'})
      const ideMenu = new nw.Menu()
      const debugMenu = new nw.Menu()
      if (global.isDevWindow) {
        debugMenu.append(new nw.MenuItem({
          label: locales.config.MENU_INSPECT_APP,
          click: () => global.Win.showDevTools(),
        }))
      } else {
        debugMenu.append(new nw.MenuItem({
          label: locales.config.MENU_INSPECT_APP,
          click: () => {
            chrome.developerPrivate.openDevTools({
              renderViewId: -1,
              renderProcessId: -1,
              extensionId: chrome.runtime.id
            })
          },
        }))
      }
      ideMenu.append(new nw.MenuItem({
        label: locales.config.MENU_INSPECT,
        submenu: debugMenu,
      }))
      ideMenu.append(new nw.MenuItem({
        label: locales.config.CLOSE_WINDOW,
        click: () => global.Win.close(true),
      }))
      ideMenu.append(new nw.MenuItem({
        label: locales.config.MENU_EXIT,
        click: () => nw.App.quit(),
      }))
      menu.append(new nw.MenuItem({
        label: locales.config.MENU_TITLE_APP,
        submenu: ideMenu,
      }))
      global.Win.menu = menu
    }
  } catch (err) {}
}
function init() {
  const Win = global.Win
  Win.on('new-win-policy', (frame, url, policy) => {
    policy.ignore()
  })
  Win.on('close', () => {
    console.log(222222);
    alert(1111)
    // make all webviews invisible
    const webviews = document.querySelectorAll('webview')
    for (const webview of webviews) {
      try {
        webview.style.display = 'none'
      } catch (e) {
        // nothing to do
      }
    }
    global.windowMap.forEach((win) => {
      try {
        if (win !== Win) {
          win.close(true)
        }
      } catch (e) {}
    })
    global.windowMap.clear()
    if (global.isDevWindow) {
      // dev window
      const clientWindowSync = require('../js/881e653f19d837f2408386047cb8c38c.js')
      clientWindowSync.notifyCloseWindow()
      Win.close(true)
    } else {
      // original main window
      const serverWindowSync = require('../js/b543ae2da406cea63b3ad8951f17b6c0.js')
      if (serverWindowSync.clientWindows.size > 0) {
        Win.hide()
      } else {
        // 几秒之后项目窗口数还是 0 说明没有正在打开的窗口了,可以正常退出
        Win.hide()
        setTimeout(() => {
          if (serverWindowSync.clientWindows.size === 0) {
            tools.quit()
          }
        }, 2000)
      }
    }
  })
  // 打开 inspect 窗口
  if (nw.App.argv.indexOf('inspect') !== -1) {
    tools.openInspectWin()
  }
  // enter background
  if (query.simple) {
    require('../js/8524207e9ea0bd06cec5e97c74bd6b7d.js')
  } else {
    require('../js/29cbb96f0d87ca0a3ee63c5dbbd8107c.js')
  }
}
hack()
initGlobal()
initMenu()
if (!global.isDevWindow && !global.online) {
  const checkUpdate = require('../js/e5184416014aff2809a9dee32cc447c8.js')
  checkUpdate.loop()
  // 检查是否需要更新
  tools.checkUpdateApp()
    .then(() => {
      init()
    })
} else {
  init()
}

在这里你会发现一个叫做initMenu的函数,不过查看之下会发现只是一个简单的Menu,不过你可以看到有一个关键文件,84b183688a46c9e2626d3e6f83365e13.js,打开后你会失望,因为它混淆并且压缩了,代码基本不可读,原本想着直接调用刷新的函数,现在想来也不好使,没办法继续回到index.js的查看,会发下一个叫做global的对象,这个对象我打印了一下,并没有找到存在刷新的关键字例如ref,在要放弃的时候发现了新大陆,win对象。这个对象如果在win里那就是窗口的意思,然后把win打印一下,出现了一个另人激动的子对象Menu,逐级查找,最终确定了刷新按钮的事件:global.Win.menu.items[2].submenu.items[2].click();。不过即使有了这个事件,还是无法与外界程序沟通更别提phpstorm了,因为这个global对象是在微信开发者工具里的,外部是无法调用的,即使你在往里写一个js那还是无法调用,后来思考改造一下微信开发者工具的cli和http接口调用的方式,加入一个自己的接口,先说cli,这个我实现了一下,发现不可行,因为其中的global并没有在cli进行实现,调用的时候直接抛出错误,然后我又想着改微信开发者工具http的调用,发现依然不行,因为提示没有我新新增的命令,在查找的过程中发现http又被微信混淆了,代码基本没法读,没办法。所以采用了一种折中的方式,自己实现http,然后在自己的端口进行监听,并且刷新。然后你就可以开发phpstorm插件,调用这个路径,进行刷新了,phpstorm插件的编写方法,搜索本博客也有记载。

http.createServer(function(request, response){
  global.Win.menu.items[2].submenu.items[2].click();
    response.writeHead(200, { 'Content-Type': 'text-plain' });
    response.write('<head><meta charset="utf-8"/></head>');
    response.end('我刷新了微信开发者工具...\n');
}).listen(2019);


最终的效果图:


Untitled1.gif


随机字符串生成

原理是利用二进制的或与操作,注意二进制的数据的位数不能冲突。例如

1 = 0001

2 = 0010

3 = 0011

1和3就是冲突的,因为最后一位都是1


<?php

$p1=1;//数字
$p2=2;//小写字母
$p3=8;//大写字母

$var_p=$p1|$p3;

$len=6;

$sour=[];

if(($var_p & $p1) == $p1)
    array_push($sour,"012345");
if(($var_p & $p2) == $p2)
    array_push($sour,"abcdef");
if(($var_p & $p3) == $p3)
    array_push($sour,"ABCDEF");

$str="";

for($i=0;$i<$len;$i++)
    $str.=substr($sour[rand(0,count($sour)-1)],rand(0,$len-1),1);

echo $str;