Saber 酱的抱枕

Fly me to the moon

07/15
2016
学习

关于PHP操作文件时最长文件名的研究

先吃我大鼻孔

今天我在改进pixiv下载器,想把tag信息保存到文件名里。前两天我研究了“windows中文件名最大长度的问题”,也是为这个做准备。我很快把获取tag的代码写好了,也在php里限制了文件名最大长度。但是做完之后感觉有点不对劲。怎么不对劲呢?下载图片的失败几率比以前大大提高了。错误都是:

Warning:fopen() Invalid argument

那么到底文件名哪里不对呢?这问题折腾了我五六个小时,我下班都没回去,坐在办公室里还在研究这个问题。天见可怜,我终于还是找到了问题的真相。

问题还是出在长度上。

windows计算文件名(包括路径)都是按【字数】算的,也就是说,不管你是中英混合还是怎么的,都能写满256个字。

我以为用php去创建文件也可以这样,于是我在php里用mb_strlen()函数去计算字数,这个函数也是把一个文字当做一个长度算。结果我这样做是错的,php虽然也会限制文件名和路径长度之和不能超过256个字符,但它真的只是字符长度,不是字数。所以php里操作文件时,涉及到文件名长度,要使用strlen()函数。

strlen()的计算方法是,英文占一个字符,而中文字符在gbk编码中算两个字符,在utf8编码中算三个字符。还好我使用的gbk编码,否则能用的字数要更少了。

下面这个路径在php的gbk编码中算做256长度(字节?):

F:\wamp\www\t/pixivimg/专辑1422_ 【一无所有的“死亡回归”!】Re 从零开始的异世界生活特辑 /56938050_p0_tag-ナツキスバル,Re ゼロから始める異世界生活,スバル,菜月昴,ゼロから始める異世界生活,リゼロ,リゼロ500users入り,Re ゼロから始める異世界00usersxxxxxxx入り.jpg

当然,用windows的计算方式,刚到170个长度。

好吧……为了在有限的长度里多给tag腾腾地方,我把文件名里很多东西都去掉了。标题啊,日期啊什么的都扔了,只留下图片id和tag。现在的文件名是这样的:

19566474_p0-よんでますよ、アザゼルさん。,十点じゃ足りません!,ふつくしい,なにこれ綺麗,サラマンダーwwwwww,一体だけ浮いてるw,まんまですよ、マンダはん,アザゼルさん1000users入り,キャプショ.jpg

这个长度已经接近极限了。心好累,感觉不会再爱了。

关于PHP操作文件时最长文件名的研究

07/15
2016
学习

php中如何判断字数

最近有个功能需要判断字数。PHP 中有很多函数可以计算字符串的长度,如strlen,mb_strlen,mb_strwidth。测试如下:

echo strlen("你好ABC") . "";
# 输出 9
echo mb_strlen("你好ABC", 'UTF-8') . "";
# 输出 5
echo mb_strwidth("你好ABC") . "";
#输出 7

可以看出,strlen 把中文字符算成3个字节;mb_strlen 不管中文还是英文,都算1个字节;而 mb_strwidth 则把中文算成2个字节。

我需要的是字数而不是字节数,所以mb_strlen是我想要的。但是要注意,“把汉字算做1个长度”必须指定为utf-8编码,否则它也会把汉字算做3个字节。

另外,截取字符串时,也可以用mb_substr指定utf-8编码,将汉字算做一个长度。如:

echo mb_substr('这样一来我的字符串就不会有乱码^_^', 0, 7, 'utf-8');

这个输出需要页面环境有编码才不会乱码。例如将此结果输出到html中,输出的字符会使用html页面的编码。如果单独写这一行php输出,还会是乱码。

php中如何判断字数

07/11
2016
软件

QWQ~Tickeys:按键时发出冒泡声/打字机声/机械键盘声~等!

如题。官方网站,全桌面平台哟~!
以下是所有的声音种类:

Tickeys' sounds

Tickeys' sounds


补充:Windows 版本 和 OS X 版本所携带的声音种类有所不同。
Tickeys in Windows

Tickeys in Windows

原本是想弄出机械键盘的声音的,结果发现最喜欢的居然是冒泡声 23333

QWQ~Tickeys:按键时发出冒泡声/打字机声/机械键盘声~等!

07/11
2016
学习

HTML5中的跨文档消息传递

我们可以使用HTML5的postMessage()方法进行跨文档的消息传递,不会触发跨域问题。

例如,我们可以在父窗口中向iframe里的页面或通过window.open()打开的页面发送消息(不仅限于文本数据),这两个页面不必是同源的(跨域可以,不跨域也可以)都不会触发跨域问题。

例如我在当前页面加载了下面的iframe页面:

<iframe src="http://127.0.0.1/t/index.html" id="f1"></iframe>

我们想要向它发送消息,该怎么做呢?

想要实现通信,首先得在接收页面里添加对消息的处理功能。postMessage()发送到页面时会触发message事件,我们在子页面绑定这个事件:

window.addEventListener("message",function(event){
	if (event.origin == "http://www.saber.love"){//确保发送消息的域是已知的域
		alert(event.origin+"说:"+event.data);//处理接收到的数据
		// event.source.postMessage("Received!", "http://www.saber.love");//可选:向来源窗口发送回执
	}
},false);

这样当消息发送到子页面时,子页面就能够处理了。

当触发message事件时,有一些有用的信息:
event.origin:发送消息的文档所在的域;
event.data:postMessage()发送过来的消息;
event.source:发送消息的文档的window 对象的代理。

之后我们在父页面向子页面发送消息,代码如下:

var iframeWindow = document.getElementById("f1").contentWindow;
iframeWindow.postMessage("hello~", "http://127.0.0.1"); //第二个参数指定【接收方】必须是指定的域

子页面接收到消息后就会进行处理:

到这里一个简单的通信就完成了。

这个例子中的通信是单向的,如果要做成子页面也向父页面返回消息,那么父页面也得绑定message事件才行。

不过我有个疑惑,子窗口似乎不能主动用postMessage向父窗口发送消息。只能在接收消息后趁机发送吗?

HTML5中的跨文档消息传递

07/10
2016
学习

向表单的select控件中添加选项

select控件就是下拉选择框,之前我没怎么试过对它进行js操作。今天看到有个add方法,可以向select控件里添加选项(option),记录一下。

var selectE=document.createElement("select");
selectE.id="selectE";
document.body.appendChild(selectE);

var optionE=document.createElement("option");
optionE.text="optionE";
selectE.add(optionE);

上例演示了创建一个select控件并像其中添加了一个选项。在需要使用JavaScript创建控件时很有用。

add语法:

selectObject.add(option,before)

option就是option元素,before是个数字,指示新选项插入在第几个选项之前。

向表单的select控件中添加选项

07/8
2016
学习

简单的仿一下商务通效果

<img src="/f/head15.jpg" id="stwRight">
<img src="/f/saber%E8%A1%A8%E6%83%85_1_1.jpg" id="stwCenter">
<img src="/f/x.png" id="swtClose">
<style type="text/css">
	#LRdiv0,#LRdiv1{display:none !important;}
	#stwRight{position: fixed;right: 0;top: 60px;display: none;z-index: 999;cursor: pointer;}
	#stwCenter{position: fixed;display: none;width: 400px;height: 350px;left: 50%;margin-left: -200px;top: 50%;margin-top: -175px;z-index: 999;cursor: pointer;}
	#swtClose{position: fixed;display: none;width: 24px;height: 24px;left: 50%;margin-left: 175px;top: 50%;margin-top: -175px;z-index: 9999;cursor: pointer;}
</style>
<script type="text/javascript">
	window.onload=function(){
		function showSwtC(){
			document.getElementById("stwCenter").style.display="block";
			document.getElementById("swtClose").style.display="block";
		}
		function showSwtR(){
			document.getElementById("stwRight").style.display="block";
		}
		function hideSwtC(){
			document.getElementById("stwCenter").style.display="none";
			document.getElementById("swtClose").style.display="none";
		}
		function hideSwtR(){
			document.getElementById("stwRight").style.display="none";
		}
		function openSwt(){
			LR_HideInvite();openZoosUrl();return false;
		}

		showSwtR();
		setTimeout(function(){
			hideSwtR();
			showSwtC();
		},4000);
		document.getElementById("stwRight").onclick=function(){
			openSwt();
		}
		document.getElementById("stwCenter").onclick=function(){
			hideSwtC();
			showSwtR();
			openSwt();
			setTimeout(function(){
				hideSwtR();
				showSwtC();
			},8000);
		}
		document.getElementById("swtClose").onclick=function(){
			hideSwtC();
			showSwtR();
			setTimeout(function(){
				hideSwtR();
				showSwtC();
			},8000);
		}
	}
</script>

侧边浮窗没做关闭按钮。

因为openSwt()里用了商务通自带的函数openZoosUrl(),所以页面上还是得加载商务通代码。如果把openSwt()改成直接用网址跳转,则不用加载商务通代码。


上面商务通不仅样式是我们自己做的,显示、隐藏的逻辑也需要自己定义。实际上对于有商务通代码的页面,我们可以直接利用商务通自身的函数来“偷梁换柱”,打开我们自己的商务通图片。

var sTimer = setInterval(function(){
	if(typeof LR_showInviteDiv != "undefined"){
		window.LR_showInviteDiv = function(){	//此处改写了商务通显示邀请框的函数	
			showSwt();
		}
		clearInterval(sTimer);
	}
},100);

LR_showInviteDiv是显示邀请框的函数,如果页面上有这个函数,则改写它,让它执行showSwt,也就是我们自己定义的一个函数,显示自己的邀请框。

恩……我对这这个代码研究了好久,发现这个办法并没有多方便,浪费时间。唯一的优点是不用写css来隐藏商务通的邀请框了。另外改写商务通的这个函数会导致商务通客户端发送邀请失败。麻烦。

简单的仿一下商务通效果

07/7
2016
其他

闲聊 关于理想

小学时一个女生问我,你的理想是什么?

十年过去了,我至今仍然无法回答。

理想是没有的,有的只是妄想。例如想和自己喜欢的人在一起什么的。

因为我是死宅,所以这注定是妄想。

不知道各位的理想又是什么呢?来聊一聊吧

闲聊 关于理想