我则要让他名正言顺的话,那就是骗人,我自己也受到不好的结果,而我在想我为何要这样做呢,我图个什么,难道就是朋友关系就可以搞定嘛,我不是在自己欺骗自己嘛,自己很不想做的事情为何要去做呢,我想问自己为什么要去招惹不就是想有个好的结果嘛,但这种结果往往得经过考验,但我觉得这样的考验也太那个了吧。。 。
大话西游里面有个叫做什么:何必呢,何必呢
天下本无事,凡人自己找之。。。
郎怪郎——原来如此。
各自搞(儿)——自己。
杂费席——好得很。
达刀(儿)——女孩的辫子。
千翻(儿),腰元(儿)——淘气,不守规矩。
卧何祸——完了,不行了。
光胩,光把胴(儿)——裸体。
舅子灯(儿)——这事没办好。
恁个(儿 ),浪个(儿)——这个,那个。
那份批心子,那份批壳——那个东西不好。
期饭——吃饭
幢天儿——昨天
打牙祭——吃肉.
帽耳坨——满碗的干饭.
恁丁丁(儿)——很少
脏班子——丢面子
砍脑壳的——找死
哈打——晚上
夹包——荷包
旯旯——角落
各搞(儿)——买肉
夹马夹胩的,溅像——小气
胶子(塑料)桶桶 —— 塑料口袋
云中—— 中午12点
哄子个___什么东西?
啷个搞嘛___怎么办嘛?
煞割了___结束了
你等到哈哈——你等一会。
回即——回去
在状子——在干什么
奶呆——好脏
耐(nai)——烫
凼凼——水坑
出托——打死你
暴消——东西坏了
想精想怪滴——胡思乱想
出去达——出去了
走达——走了
吃达——吃了
哄子批个——什么东西个?
马翻批——说话不算数,一会这样,一会那样!
丕脱——不讲究,不讲排场!
状子——什么
你在爪子——你在干什么
瞎明避眼,瞎明倒眼——看不见(骂人的)
扯皮、扯把子——乱搞。
办灯——不认真。
灯多——办法多。
打不死九不干——不讲理,乱扯。
柳倒起——死皮赖脸不放。
片给你——送给你。
不落屋——不回家。
盘餐——路费。
欠狗(儿)——胃痉挛。
喝害——哈欠
对窝(儿)——碓。
对窝(儿)——对头。
皮款、银子、子弹、米米、恁恁(儿)——钞票。
酸不流秋、冒酸——故弄玄虚。
出十气——出丑.
鸠巴蛋——小。
蛮——大或耍很横
。歹倒——捉倒。
扣痒——扰痒。
猫煞——美好,很不错。
日烟儿——美好,很不错
匡娃二——逗小孩不哭或睡觉。
打么灯(儿)——给脸上摸红(化装)。
藏猫猫——捉迷藏。
拽(一声)——洋气,看不起人。
超——打扮特别。
打白——赌气。
哈(三)人,赫人——吓人。
少活间——中午
骚冲——气质高
过早——吃早饭前的小吃。
过午、打腰战——午饭前的小吃。
煮开水(客人来了)——荷包蛋、小汤圆之类。
消夜——吃晚饭。
握火——烧火或烧屋外的垃圾。
哈打——黑了。
区猫哈——黑得很。
日起跛(bong)起先下课。
哄你、喝你、麻你、敷你——骗你。
喝你——巴结你。
决你——骂你。
麻了、况了——酒喝多了点的感觉。
晃——故弄弦虚或做人、办事不踏实。
黄的——没把握。
慌的——不清醒。
达铁——思维受阻。
走火——开小差。
铁老壳——不怕事、顽固。
趴——软
闹药(yo)——毒药。
麻利、麻溜——快。
达扑爬——跌跤。
眵、盯(三声)——看
暗些——10点左右的时候
格老子——有点生气
走哪儿气——到哪里去
气饭麦——吃饭了没
搞啥子明堂——在做什么?
罗——烫、煎(罗粑粑,罗糍粑)
困瞌睡——睡觉
光脑壳——下雨或者下雪或者夏天出门不代伞的情况
哭倒——蹲。
查起——双腿分开。
排(四声)起——双臂分开。
挝你——踢你。
初人——说话语气重,不礼貌。
渣丫八胩——不好看的动作。
威起——无精神。
耸起——怕人、怕冷的样子。
冒泡、日白——吹牛、说大话。
龟儿子——王八(骂人的话了)
楼脚——楼下。
透(儿)脚——底下。
歇房屋、房圈屋、地庆(儿)
屋——寝室。 毛房——厕所。
灶房屋——厨房。 陶屋——客厅。
以前偷工减料,到处乱抄东西,现在要几大原则同时进行:
1.不谈个人的情感
2.不谈私生活
3.不谈他人软肋
谈什么:
2.谈技术
3.谈生活
文章出处: http://php.cublog.cn
其实这并不是什么光彩的事,我原来所在的公司因为民营企业的死亡率最高的原因:资金链断裂而死亡。在近半年没有领到工资之后,终于在公司办公场所即将到期之前决定重新找份工作。
先自我介绍一下,我是一个开源CMS开发组的领导者和核心开发人员之一,开发了大约70%核心部分的代码。能够在linux下完成除图像处理以外的日常工作。我不敢说什么精通,但是至少该会的都会了。个人能力是:
PHP
XHTML + CSS
JAVAScript
C
shell


class man{
var $sex="男";
var $heigh=1010;
var $weight;
function run(){
echo "I am run !";
}
function sleep($sexs){
echo "I am sleep";
$this->sex=$sexs;
}
}
?>
<?php
$xiangdong=new man();
$xiangdong->sleep(女);
echo "$xiangdong->sex";
echo "$xiangdong->heigh";
echo "$xiangdong->heigh";
echo "$xiangdong->run()--------------";
echo $xiangdong->sleep("男的啊");
$xiangdong->sex;
$serialize=serialize($xiangdong);
echo "序列化后的结果:<br> ";
echo $serialize;
echo " 开始反序列化:";
$unserialize=unserialize($serialize);
echo $unserialize->sex;
echo "<br>";
echo "$unserialize->sleep(\"男的a啊\")";
?>
select count(*) from question as q where q.o_id not in (select answer.o_id from answer) and q.q_status!='del' order by q_id
user表:
id | name
———
1 | libk
2 | zyfon
3 | daodao
user_action表:
user_id | action
—————
1 | jump
1 | kick
1 | jump
2 | run
4 | swim
sql:
select id, name, action from user as u
left join user_action a on u.id = a.user_id
result:
id | name | action
——————————–
1 | libk | jump ①
1 | libk | kick ②
1 | libk | jump ③
2 | zyfon | run ④
3 | daodao | null ⑤
分析:
注意到user_action中还有一个user_id=4, action=swim的纪录,但是没有在结果中出现,
而user表中的id=3, name=daodao的用户在user_action中没有相应的纪录,但是却出现在了结果集中
因为现在是left join,所有的工作以left为准.
结果1,2,3,4都是既在左表又在右表的纪录,5是只在左表,不在右表的纪录
结论:
我们可以想象left join 是这样工作的
从左表读出一条,选出所有与on匹配的右表纪录(n条)进行连接,形成n条纪录(包括重复的行,如:结果1和结果3),
如果右边没有与on条件匹配的表,那连接的字段都是null.
然后继续读下一条。
引申:
我们可以用右表没有on匹配则显示null的规律, 来找出所有在左表,不在右表的纪录, 注意用来判断的那列必须声明为not null的。
如:
sql:
select id, name, action from user as u
left join user_action a on u.id = a.user_id
where a.user_id is NULL
(注意:1.列值为null应该用is null 而不能用=NULL
2.这里a.user_id 列必须声明为 NOT NULL 的)
result:
id | name | action
————————–
3 | daodao | NULL
——————————————————————————–
Tips:
1. on a.c1 = b.c1 等同于 using(c1)
2. INNER JOIN 和 , (逗号) 在语义上是等同的
3. 当 MySQL 在从一个表中检索信息时,你可以提示它选择了哪一个索引。
如果 EXPLAIN 显示 MySQL 使用了可能的索引列表中错误的索引,这个特性将是很有用的。
通过指定 USE INDEX (key_list),你可以告诉 MySQL 使用可能的索引中最合适的一个索引在表中查找记录行。
可选的二选一句法 IGNORE INDEX (key_list) 可被用于告诉 MySQL 不使用特定的索引。
4. 一些例子:
mysql> SELECT * FROM table1,table2 WHERE table1.id=table2.id;
mysql> SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id;
mysql> SELECT * FROM table1 LEFT JOIN table2 USING (id);
mysql> SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id
-> LEFT JOIN table3 ON table2.id=table3.id;
mysql> SELECT * FROM table1 USE INDEX (key1,key2)
-> WHERE key1=1 AND key2=2 AND key3=3;
mysql> SELECT * FROM table1 IGNORE INDEX (key3)
-> WHERE key1=1 AND key2=2 AND key3=3;
7.2.9. MySQL如何优化LEFT JOIN和RIGHT JOIN
在MySQL中,A LEFT JOIN B join_condition执行过程如下:
· 根据表A和A依赖的所有表设置表B。
· 根据LEFT JOIN条件中使用的所有表(除了B)设置表A。
· LEFT JOIN条件用于确定如何从表B搜索行。(换句话说,不使用WHERE子句中的任何条件)。
· 可以对所有标准联接进行优化,只是只有从它所依赖的所有表读取的表例外。如果出现循环依赖关系,MySQL提示出现一个错误。
· 进行所有标准WHERE优化。
· 如果A中有一行匹配WHERE子句,但B中没有一行匹配ON条件,则生成另一个B行,其中所有列设置为NULL。
· 如果使用LEFT JOIN找出在某些表中不存在的行,并且进行了下面的测试:WHERE部分的col_name IS NULL,其中col_name是一个声明为 NOT NULL的列,MySQL找到匹配LEFT JOIN条件的一个行后停止(为具体的关键字组合)搜索其它行。
RIGHT JOIN的执行类似LEFT JOIN,只是表的角色反过来。
联接优化器计算表应联接的顺序。LEFT JOIN和STRAIGHT_JOIN强制的表读顺序可以帮助联接优化器更快地工作,因为检查的表交换更少。请注意这说明如果执行下面类型的查询,MySQL进行全扫描b,因为LEFT JOIN强制它在d之前读取:
SELECT *
FROM a,b LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key)
WHERE b.key=d.key;

安装方法和软件包都放在里面自己慢慢看这安装吧:
点击下载它吧
--by dong made in china
珠宝专业书籍:[url=http://www.edu.cn/20040118/3097835.shtml]http://www.edu.cn/20040118/3097835.shtmlhttp://zhidao.baidu.com/question/8352678.html?fr=qrl3[/url]
中国地质大学珠宝学院 >> 学院介绍:
http://unit.cug.edu.cn/zbxy/Article_Show.asp?ArticleID=246
中国地大华南科技学院首创珠宝鉴定专业:
以上仅仅功参考。。。。
这一次的问题是关于C语言的main主函数所带的参数问题,幸而下课时一旁的老师听见了,及时的帮我了个大忙,其实这个问题我也胡里胡涂.现在清楚多了.
每个应用程序后面都可以跟一些参数来控制程序初始化的状态.
看以下程序
程序代码
#include
void main(int argc, char *argv[])
{
int i;
for(i = 0; i < argc; i++)
printf("%s%s", argv[i], (i < argc - 1) ? " " : "");
printf("\n");
}
这个简单的程序什么都不干,只是将接收到的函数参数原原本本的打印出来,让我们看清楚我们的参数是如何被应用程序调用的.
int argc代表整形的传入的参数个数
char *argv[]代表指向传入的字符型参数地址的指针变量,通过访问这些指针,我们能得到传入的是什么
让我们输入一些参数来测试吧
切忌在命令行下进行操作,不然怎么加参数呢
什么?命令行是什么?
Windows NT/XP及以上用户运行cmd
Windows 98/Me及以下用户运行command(用这些操作系统的可以列为国家保护动物了)
命令行下直接输入程序名:我这里叫test(.exe)
程序返回的确实是所在磁盘路径D:\TURBOC2\WORKING\TEST.EXE
输入test 123
返回D:\TURBOC2\WORKING\TEST.EXE 123
就从以下的作业,基本可以看出,中国的大学与北美的大学在培养学生能力方面的不同。不错,北美的一些学生是笨,而且有的笨得可以,但笨不是全部,他们最后成绩可能不好,但很多思维方法与习惯都在不自觉中掌握了。而北美社会是个自由的社会,每个人都可以做他愿意做的事,只要你能做,你不会的事可以不做。而中国的大学生呢?往往是越是成绩好越是只会考试,别的反而什么都不会,这不是畸形吗?结果走上社会时除了成绩好没有什么优点,在工作中往往不能胜任,当然中国好一点是有些时间给你慢慢学,北美就没这么幸运了,你不行就被淘汰了。
在写程序方面,我觉得大多数中国的程序员写的很多程序都没有什么水平,象小孩写的东西,一点不象是专业人士写的。比如我前几天看到一个程序被作者冠为“最好的PHP的EMAIL的类”这么一个程序,一看,无非就是实现了规范要求的格式,最后通过SOCK发送出去。本来也没什么,但一看,居然一个缩进都没有,而且逻辑混乱,功能不紧凑单一,还被称为最好的,当时狂吐,中国的高手程序员都死绝了?!总之就是从一开始就没有培养好规范的作风与思考与分析问题解决问题的能力,结果就是大多数中国的程序员从来就是不入流的(指正规的专业人士),一个明显的表现就是中国根本缺乏世界著名的品牌,也很少有什么著名的大公司,一些著名的软件也大都只是小软件,没有大系统大制作,这与国外差得太远了,主要原因是没有人有能力搞这些,也没有人有长远的眼光进行投资。还有就是搞得太杂,结果是什么都做不好。而且中国的软件做得是实在是太小儿科不说,用户也不友好,运行也不稳定,好象压根没做什么严格测试的,试想一些所谓的中型程序一个人搞一个月就出台,还美其名曰高效,怎么可能?想FLASHGET这样的程序也不是只一个月能搞定的吧?光过硬的调试可能就花掉一个月,更别谈从设计到写码到成型到调试到测试到发布了。文档更是做得极差,有的连说明都没有,搞得人无所适从。国外的软件,无论是多大多小的程序,一般都有说明,至少是安装使用的简单说明——就是一般的文本,至少能让你入手。国人的程序唯一一个优点就是程序是中文的——但这往往比用英文软件还要不方便。比如说,我前几天装一个邮件服务器,一开始用国人写的某“著名”软件,一装,首先就感觉运行不流畅,打开界面一看,连最重要的STMP发送认证都找不到在哪儿,界面极其简陋,功能严重欠缺,安全性方面更不知道可不可靠了,看帮助也看不清,后来在一个与安全无关的地方找到了选项,再一看,很多基本策略都没有,无法保证安全性。直摇头,马上uninstall,后来装了MD,虽然是英文,但结构清楚,功能齐全,工作明显稳定很多,而且帮助文档、使用手册极其详细,有的还有概念解释,以方便非专业用户。虽然支持国产,但是国产不争气,没有办法。
其实下面的问题很简单,一个人做根本不用那么复杂,但是让一组人来协调地做,还真不是那么简单的事,要有一个有分析头脑的人做leader,要有人专门负责写文档,有人测试什么的。对了,这门课好象就是software engineering,软件工程,好象中国是不学的吧,至少我那时没学。
------------------ 这是这位朋友本周要做的任务 ----------------
- 2.5 Assumptions and Dependencies.
What do you assume the client to do/act/want, and what you depend on to produce a final result. Its design phases for everyone.
---------------------- 以下是原题目 ---------------------------
Dominion Pizza Store
• Objectives:
o Dominion Pizza Store (DPS) is planning an information system for their services. A customer may make an order through the Internet / Phone / in-person. The order may include several products. There are a few basic sorts of pizzas, which can be complemented with different toppings. The assortment and the toppings change from time to time, as do their prices. In addition to pizzas, other products are on offer. They are divided into product groups. There is a textual description of every product, and a picture of some of them, which the client may see when ordering through the WWW.
o A bill will accompany each delivery. The price will be discounted according to time, if the delivery is late; for example, 45-minute delivery or FREE. The price of a product may, also, differ according to the time of day, for example. The time and place of delivery is set when the customer makes the order.
o For an online / phone order, the customer is identified by his/her telephone number, or other contact information. A delivery status time stamp (i.e. to kitchen, to delivery, and to customer) is registered for each delivery. The client may cancel or change the order only if the order has not gone to the kitchen. For an online/phone order, customer's information is checked in the database for an existing, or new client. If the client is new then take and store contact details. For an existing client (or address), past history will be checked for any problems.
• Main Modules:
1. Client Interface
Browsing the Products, and their Prices
Making an order
Delivery time stamping
2. Agent Interface (Phone / in-person orders)
Entering Agent Info (e.g. ID)
Browsing the Products, and their Prices
Delivery time stamping
Checking past history (for any problems, and/or past frequent orders for either quick order taking or special offers)
3. Inventory Management
Food supplies
Misc. supplies (e.g. Cleaning)
Entering and maintaining product information (inc. pricing) in the database
4. Finances Management
Account Receivables
Account Payables
5. Delivery Management
Order Status (i.e. to kitchen - when, to delivery - when)
Special offers (e.g. late order, new product introduction)
Printing an order list - for kitchen (?)
Printing a receipt
6. Payroll
Employee Information (e.g. Contact Info, Salary Info, Bonuses, Taxes, GST/PST)
Hiring / Firing / Training etc.
7. Anything you may suggest (will be considered towards the Bonus Marks for the best project, if above modules done reasonably well
其实网上搜索有不少 MP3 的类似程序,但 WMA 的几乎没有,如果有也是windows平台下直接使用API的,想在 Unix/Linux 下使用简直没门。。。。
由于我的音乐站刚开通,需要这方面的功能,所以就下决心花时间去查资料搞清楚MP3和wma的数据头格式,全部代码由PHP编写,有兴趣可以仔细研究,或加以完善。
其实这东西技术上并没有难点,麻烦在于先要搞清楚它的结构和格式,这个代码也是一个使用PHP操作二进制(binary data)的例子,这几天群里刚好也有人问起这个,主要就是pack和unpack2个函数啦,呵呵,像MP3的原始头信息几乎是一个bit表示一个信息,这时就要用到大量的“按位操作”来分析它。
下面是源码照贴(含例子),呵,这也作为实习版主的一个小贡献吧,挺希望这里能见到一些原创并且对它人有用的代码(类库)出现。!!在此抛砖先了。
// AudioExif.class.php
// 用PHP进行音频文件头部信息的读取与写入
// 目前只支持 WMA 和 MP3 两种格式, 只支持常用的几个头部信息
//
// 写入信息支持: Title(名称), Artist(艺术家), Copyright(版权), Description (描述)
// Year(年代), Genre (流派), AlbumTitle (专辑标题)
// 其中 mp3 和 wma 略有不同, 具体返回的信息还可能更多, 但只有以上信息可以被写入
// mp3 还支持 Track (曲目编号写入)
// 对于 MP3 文件支持 ID3v1也支持ID3v2, 读取时优先 v2, 写入时总是会写入v1, 必要时写入v2
//
// 用法说明: (由于 wma 使用 Unicode 存取, 故还需要 mb_convert_encoding() 扩展
// 返回数据及写入数据均为 ANSI 编码, 即存什么就显示什么 (中文_GB2312)
//
// require ('AudioExif.class.php');
// $AE = new AudioExif;
// $file = '/path/to/test.mp3';
//
// 1. 检查文件是否完整 (only for wma, mp3始终返回 true)
//
// $AE->CheckSize($file);
//
// 2. 读取信息, 返回值由信息组成的数组, 键名解释参见上方
//
// print_r($AE->GetInfo($file));
//
// 3. 写入信息, 第二参数是一个哈希数组, 键->值, 支持的参见上方的, mp3也支持 Track
// 要求第一参数的文件路径可由本程序写入
// $pa = array('Title' => '新标题', 'AlbumTitle' => '新的专辑名称');
// $AE->SetInfo($file, $pa);
//
// 版本: 0.1
// 作者: hightman
// QQ群: 17708754 (非纯PHP进阶交流群)
// 时间: 2007/01/25
// 其它: 该插件花了不少时间搜集查找 wma及mp3 的文件格式说明文档与网页, 希望对大家有用.
// 其实网上已经有不少类似的程序, 但对 wma 实在太少了, 只能在 win 平台下通过 M$ 的
// API 来操作, 而 MP3 也很少有可以在 unix/linux 命令行操作的, 所以特意写了这个模块
//
// 如果发现 bug 或提交 patch, 或加以改进使它更加健壮, 请告诉我.
// (关于 ID3和Wma的文件格式及结构 在网上应该都可以找到参考资料)
//
if (!extension_loaded('mbstring'))
{
trigger_error('PHP Extension module `mbstring` is required for AudioExif', E_USER_WARNING);
return true;
}
// the Main Class
class AudioExif
{
// public vars
var $_wma = false;
var $_mp3 = false;
// Construct
function AudioExif()
{
// nothing to do
}
// check the filesize
function CheckSize($file)
{
$handler = &$this->_get_handler($file);
if (!$handler) return false;
return $handler->check_size($file);
}
// get the infomations
function GetInfo($file)
{
$handler = &$this->_get_handler($file);
if (!$handler) return false;
return $handler->get_info($file);
}
// write the infomations
function SetInfo($file, $pa)
{
if (!is_writable($file))
{
trigger_error('AudioExif: file `' . $file . '` can not been overwritten', E_USER_WARNING);
return false;
}
$handler = &$this->_get_handler($file);
if (!$handler) return false;
return $handler->set_info($file, $pa);
}
// private methods
function &_get_handler($file)
{
$ext = strtolower(strrchr($file, '.'));
$ret = false;
if ($ext == '.mp3')
{ // MP3
$ret = &$this->_mp3;
if (!$ret) $ret = new _Mp3Exif();
}
else if ($ext == '.wma')
{ // wma
$ret = &$this->_wma;
if (!$ret) $ret = new _WmaExif();
}
else
{ // unknown
trigger_error('AudioExif not supported `' . $ext . '` file.', E_USER_WARNING);
}
return $ret;
}
}
// DBCS => gb2312
function dbcs_gbk($str)
{
// strip the last "\0\0"
$str = substr($str, 0, -2);
return mb_convert_encoding($str, 'GBK', 'UCS-2LE');
}
// gb2312 => DBCS
function gbk_dbcs($str)
{
$str = mb_convert_encoding($str, 'UCS-2LE', 'GBK');
$str .= "\0\0";
return $str;
}
// file exif
class _AudioExif
{
var $fd;
var $head;
var $head_off;
var $head_buf;
// init the file handler
function _file_init($fpath, $write = false)
{
$mode = ($write ? 'rb+' : 'rb');
$this->fd = @fopen($fpath, $mode);
if (!$this->fd)
{
trigger_error('AudioExif: `' . $fpath . '` can not be opened with mode `' . $mode . '`', E_USER_WARNING);
return false;
}
$this->head = false;
$this->head_off = 0;
$this->head_buf = '';
return true;
}
// read buffer from the head_buf & move the off pointer
function _read_head_buf($len)
{
if ($len <= 0) return NULL;
$buf = substr($this->head_buf, $this->head_off, $len);
$this->head_off += strlen($buf);
return $buf;
}
// read one short value
function _read_head_short()
{
$ord1 = ord(substr($this->head_buf, $this->head_off, 1));
$ord2 = ord(substr($this->head_buf, $this->head_off+1, 1));
$this->head_off += 2;
return ($ord1 + ($ord2<<8));
}
// save the file head
function _file_save($head, $olen, $nlen = 0)
{
if ($nlen == 0) $nlen = strlen($head);
if ($nlen == $olen)
{
// shorter
flock($this->fd, LOCK_EX);
fseek($this->fd, 0, SEEK_SET);
fwrite($this->fd, $head, $nlen);
flock($this->fd, LOCK_UN);
}
else
{
// longer, buffer required
$stat = fstat($this->fd);
$fsize = $stat['size'];
// buf required (4096?) 应该不会 nlen - olen > 4096 吧
$woff = 0;
$roff = $olen;
// read first buffer
flock($this->fd, LOCK_EX);
fseek($this->fd, $roff, SEEK_SET);
$buf = fread($this->fd, 4096);
// seek to start
fseek($this->fd, $woff, SEEK_SET);
fwrite($this->fd, $head, $nlen);
$woff += $nlen;
// seek to woff & write the data
do
{
$buf2 = $buf;
$roff += 4096;
if ($roff < $fsize)
{
fseek($this->fd, $roff, SEEK_SET);
$buf = fread($this->fd, 4096);
}
// save last buffer
$len2 = strlen($buf2);
fseek($this->fd, $woff, SEEK_SET);
fwrite($this->fd, $buf2, $len2);
$woff += $len2;
}
while ($roff < $fsize);
ftruncate($this->fd, $woff);
flock($this->fd, LOCK_UN);
}
}
// close the file
function _file_deinit()
{
if ($this->fd)
{
fclose($this->fd);
$this->fd = false;
}
}
}
// wma class
class _WmaExif extends _AudioExif
{
var $items1 = array('Title', 'Artist', 'Copyright', 'Description', 'Reserved');
var $items2 = array('Year', 'Genre', 'AlbumTitle');
// check file size (length) maybe invalid file
function check_size($file)
{
$ret = false;
if (!$this->_file_init($file)) return true;
if ($this->_init_header())
{
$buf = fread($this->fd, 24);
$tmp = unpack('H32id/Vlen/H8unused', $buf);
if ($tmp['id'] == '3626b2758e66cf11a6d900aa0062ce6c')
{
$stat = fstat($this->fd);
$ret = ($stat['size'] == ($this->head['len'] + $tmp['len']));
}
}
$this->_file_deinit();
return $ret;
}
// set info (save the infos)
function set_info($file, $pa)
{
// check the pa
settype($pa, 'array');
if (!$this->_file_init($file, true)) return false;
if (!$this->_init_header())
{
$this->_file_deinit();
return false;
}
// parse the old header & generate the new header
$head_body = '';
$st_found = $ex_found = false;
$head_num = $this->head['num'];
while (($tmp = $this->_get_head_frame()) && ($head_num > 0))
{
$head_num--;
if ($tmp['id'] == '3326b2758e66cf11a6d900aa0062ce6c')
{ // Standard Info
// 1-4
$st_found = true;
$st_body1 = $st_body2 = '';
$lenx = unpack('v5', $this->_read_head_buf(10));
$tmp['len'] -= 34; // 10 + 24
for ($i = 0; $i < count($this->items1); $i++)
{
$l = $lenx[$i+1];
$k = $this->items1[$i];
$tmp['len'] -= $l;
$data = $this->_read_head_buf($l);
if (isset($pa[$k])) $data = gbk_dbcs($pa[$k]);
$st_body2 .= $data;
$st_body1 .= pack('v', strlen($data));
}
// left length
if ($tmp['len'] > 0) $st_body2 .= $this->_read_head_buf($tmp['len']);
// save to head_body
$head_body .= pack('H32VH8', $tmp['id'], strlen($st_body1 . $st_body2)+24, $tmp['unused']);
$head_body .= $st_body1 . $st_body2;
}
else if ($tmp['id'] == '40a4d0d207e3d21197f000a0c95ea850')
{ // extended info
$ex_found = true;
$inum = $this->_read_head_short();
$inum2 = $inum;
$tmp['len'] -= 26; // 24 + 2
$et_body = '';
while ($tmp['len'] > 0 && $inum > 0)
{
// attribute name
$nlen = $this->_read_head_short();
$nbuf = $this->_read_head_buf($nlen);
// the flag & value length
$flag = $this->_read_head_short();
$vlen = $this->_read_head_short();
$vbuf = $this->_read_head_buf($vlen);
// set the length
$tmp['len'] -= (6 + $nlen + $vlen);
$inum--;
// save the data?
$name = dbcs_gbk($nbuf);
$k = substr($name, 3);
if (in_array($k, $this->items2) && isset($pa[$k]))
{
$vbuf = gbk_dbcs($pa[$k]);
$vlen = strlen($vbuf);
unset($pa[$k]);
}
$et_body .= pack('v', $nlen) . $nbuf . pack('vv', $flag, $vlen) . $vbuf;
}
// new tag insert??
foreach ($this->items2 as $k)
{
if (isset($pa[$k]))
{
$inum2++;
$nbuf = gbk_dbcs('WM/' . $k);
$nlen = strlen($nbuf);
$vbuf = gbk_dbcs($pa[$k]);
$vlen = strlen($vbuf);
$et_body .= pack('v', $nlen) . $nbuf . pack('vv', 0, $vlen) . $vbuf;
}
}
// left buf?
if ($tmp['len'] > 0) $et_body .= $this->_read_head_buf($tmp['len']);
// save to head_body
$head_body .= pack('H32VH8v', $tmp['id'], strlen($et_body)+26, $tmp['unused'], $inum2);
$head_body .= $et_body;
}
else
{
// just keep other head frame
$head_body .= pack('H32VH8', $tmp['id'], $tmp['len'], $tmp['unused']);
if ($tmp['len'] > 24) $head_body .= $this->_read_head_buf($tmp['len']-24);
}
}
// st not found?
if (!$st_found)
{
$st_body1 = $st_body2 = '';
foreach ($this->items1 as $k)
{
$data = (isset($pa[$k]) ? gbk_dbcs($pa[$k]) : "");
$st_body1 .= pack('v', strlen($data));
$st_body2 .= $data;
}
// save to head_body
$head_body .= pack('H32Va4', '3326b2758e66cf11a6d900aa0062ce6c', strlen($st_body1 . $st_body2)+24, '');
$head_body .= $st_body1 . $st_body2;
$this->head['num']++;
}
// ex not found?
if (!$ex_found)
{
$inum = 0;
$et_body = '';
foreach ($this->items2 as $k)
{
$nbuf = gbk_dbcs('WM/' . $k);
$vbuf = (isset($pa[$k]) ? gbk_dbcs($pa[$k]) : "");
$et_body .= pack('v', strlen($nbuf)) . $nbuf . pack('vv', 0, strlen($vbuf)) . $vbuf;
$inum++;
}
$head_body .= pack('H32Va4v', '40a4d0d207e3d21197f000a0c95ea850', strlen($et_body)+26, '', $inum);
$head_body .= $et_body;
$this->head['num']++;
}
// after save
$new_len = strlen($head_body) + 30;
$old_len = $this->head['len'];
if ($new_len < $old_len)
{
$head_body .= str_repeat("\0", $old_len - $new_len);
$new_len = $old_len;
}
$tmp = $this->head;
$head_buf = pack('H32VVVH4', $tmp['id'], $new_len, $tmp['len2'], $tmp['num'], $tmp['unused']);
$head_buf .= $head_body;
$this->_file_save($head_buf, $old_len, $new_len);
// close the file & return
$this->_file_deinit();
return true;
}
// get info
function get_info($file)
{
$ret = array();
if (!$this->_file_init($file)) return false;
if (!$this->_init_header())
{
$this->_file_deinit();
return false;
}
// get the data from head_buf
$head_num = $this->head['num']; // num of head_frame
while (($tmp = $this->_get_head_frame()) && $head_num > 0)
{
$head_num--;
if ($tmp['id'] == '3326b2758e66cf11a6d900aa0062ce6c')
{ // Standard Info
$lenx = unpack('v*', $this->_read_head_buf(10));
for ($i = 1; $i <= count($this->items1); $i++)
{
$k = $this->items1[$i-1];
$ret[$k] = dbcs_gbk($this->_read_head_buf($lenx[$i]));
}
}
else if ($tmp['id'] == '40a4d0d207e3d21197f000a0c95ea850')
{ // Extended Info
$inum = $this->_read_head_short();
$tmp['len'] -= 26;
while ($inum > 0 && $tmp['len'] > 0)
{
// attribute name
$nlen = $this->_read_head_short();
$nbuf = $this->_read_head_buf($nlen);
// the flag & value length
$flag = $this->_read_head_short();
$vlen = $this->_read_head_short();
$vbuf = $this->_read_head_buf($vlen);
// update the XX
$tmp['len'] -= (6 + $nlen + $vlen);
$inum--;
$name = dbcs_gbk($nbuf);
$k = substr($name, 3);
if (in_array($k, $this->items2))
{ // all is string value (refer to falg for other tags)
$ret[$k] = dbcs_gbk($vbuf);
}
}
}
else
{ // skip only
if ($tmp['len'] > 24) $this->head_off += ($tmp['len'] - 24);
}
}
$this->_file_deinit();
return $ret;
}
// get the header?
function _init_header()
{
fseek($this->fd, 0, SEEK_SET);
$buf = fread($this->fd, 30);
if (strlen($buf) != 30) return false;
$tmp = unpack('H32id/Vlen/Vlen2/Vnum/H4unused', $buf);
if ($tmp['id'] != '3026b2758e66cf11a6d900aa0062ce6c')
return false;
$this->head_buf = fread($this->fd, $tmp['len'] - 30);
$this->head = $tmp;
return true;
}
// _get_head_frame()
function _get_head_frame()
{
$buf = $this->_read_head_buf(24);
if (strlen($buf) != 24) return false;
$tmp = unpack('H32id/Vlen/H8unused', $buf);
return $tmp;
}
}
// mp3 class (if not IDv2 then select IDv1)
class _Mp3Exif extends _AudioExif
{
var $head1;
var $genres = array('Blues','Classic Rock','Country','Dance','Disco','Funk','Grunge','Hip-Hop','Jazz','Metal','New Age','Oldies','Other','Pop','R&B','Rap','Reggae','Rock','Techno','Industrial','Alternative','Ska','Death Metal','Pranks','Soundtrack','Euro-Techno','Ambient','Trip-Hop','Vocal','Jazz+Funk','Fusion','Trance','Classical','Instrumental','Acid','House','Game','Sound Clip','Gospel','Noise','AlternRock','Bass','Soul','Punk','Space','Meditative','Instrumental Pop','Instrumental Rock','Ethnic','Gothic','Darkwave','Techno-Industrial','Electronic','Pop-Folk','Eurodance','Dream','Southern Rock','Comedy','Cult','Gangsta','Top 40','Christian Rap','Pop/Funk','Jungle','Native American','Cabaret','New Wave','Psychadelic','Rave','Showtunes','Trailer','Lo-Fi','Tribal','Acid Punk','Acid Jazz','Polka','Retro','Musical','Rock & Roll','Hard Rock','Unknown');
// MP3 always return true
function check_size($file)
{
return true;
}
// get info
function get_info($file)
{
if (!$this->_file_init($file)) return false;
$ret = false;
if ($this->_init_header())
{
$ret = ($this->head ? $this->_get_v2_info() : $this->_get_v1_info());
$ret['meta'] = $this->_get_meta_info();
}
$this->_file_deinit();
return $ret;
}
// set info
function set_info($file, $pa)
{
if (!$this->_file_init($file, true)) return false;
if ($this->_init_header())
{
// always save v1 info
$this->_set_v1_info($pa);
// set v2 first if need
$this->_set_v2_info($pa);
}
$this->_file_deinit();
return true;
}
// get the header information[v1+v2], call after file_init
function _init_header()
{
$this->head1 = false;
$this->head = false;
// try to get ID3v1 first
fseek($this->fd, -128, SEEK_END);
$buf = fread($this->fd, 128);
if (strlen($buf) == 128 && substr($buf, 0, 3) == 'TAG')
{
$tmp = unpack('a3id/a30Title/a30Artist/a30AlbumTitle/a4Year/a28Description/CReserved/CTrack/CGenre', $buf);
$this->head1 = $tmp;
}
// try to get ID3v2
fseek($this->fd, 0, SEEK_SET);
$buf = fread($this->fd, 10);
if (strlen($buf) == 10 && substr($buf, 0, 3) == 'ID3')
{
$tmp = unpack('a3id/Cver/Crev/Cflag/C4size', $buf);
$tmp['size'] = ($tmp['size1']<<21)|($tmp['size2']<<14)|($tmp['size3']<<7)|$tmp['size4'];
unset($tmp['size1'], $tmp['size2'], $tmp['size3'], $tmp['size4']);
$this->head = $tmp;
$this->head_buf = fread($this->fd, $tmp['size']);
}
return ($this->head1 || $this->head);
}
// get v1 info
function _get_v1_info()
{
$ret = array();
$tmpa = array('Title', 'Artist', 'Copyright', 'Description', 'Year', 'AlbumTitle');
foreach ($tmpa as $tmp)
{
$ret[$tmp] = $this->head1[$tmp];
if ($pos = strpos($ret[$tmp], "\0"))
$ret[$tmp] = substr($ret[$tmp], 0, $pos);
}
// count the Genre, [Track]
if ($this->head1['Reserved'] == 0) $ret['Track'] = $this->head1['Track'];
else $ret['Description'] .= chr($ret['Reserved']) . chr($ret['Track']);
// Genre_idx
$g = $this->head1['Genre'];
if (!isset($this->genres[$g])) $ret['Genre'] = 'Unknown';
else $ret['Genre'] = $this->genres[$g];
// return the value
$ret['ID3v1'] = 'yes';
return $ret;
}
// get v2 info
function _get_v2_info()
{
$ret = array();
$items = array( 'TCOP'=>'Copyright', 'TPE1'=>'Artist', 'TIT2'=>'Title', 'TRCK'=> 'Track',
'TCON'=>'Genre', 'COMM'=>'Description', 'TYER'=>'Year', 'TALB'=>'AlbumTitle');
while (true)
{
$buf = $this->_read_head_buf(10);
if (strlen($buf) != 10) break;
$tmp = unpack('a4fid/Nsize/nflag', $buf);
if ($tmp['size'] == 0) break;
$tmp['dat'] = $this->_read_head_buf($tmp['size']);
// 0x6000 (11000000 00000000)
if ($tmp['flag'] & 0x6000) continue;
// mapping the data
if ($k = $items[$tmp['fid']])
{ // If first char is "\0", just skip
if (substr($tmp['dat'], 0, 1) == "\0") $tmp['dat'] = substr($tmp['dat'], 1);
$ret[$k] = $tmp['dat'];
}
}
// reset the genre
if ($g = $ret['Genre'])
{
if (substr($g,0,1) == '(' && substr($g,-1,1) == ')') $g = substr($g, 1, -1);
if (is_numeric($g))
{
$g = intval($g);
$ret['Genre'] = (isset($this->genres[$g]) ? $this->genres[$g] : 'Unknown');
}
}
$ret['ID3v1'] = 'no';
return $ret;
}
// get meta info of MP3
function _get_meta_info()
{
// seek to the lead buf: 0xff
$off = 0;
if ($this->head) $off = $this->head['size'] + 10;
fseek($this->fd, $off, SEEK_SET);
while (!feof($this->fd))
{
$skip = ord(fread($this->fd, 1));
if ($skip == 0xff) break;
}
if ($skip != 0xff) return false;
$buf = fread($this->fd, 3);
if (strlen($buf) != 3) return false;
$tmp = unpack('C3', $buf);
if (($tmp[1] & 0xf0) != 0xf0) return false;
// get the meta info
$meta = array();
// get mpeg version
$meta['mpeg'] = ($tmp[1] & 0x08 ? 1 : 2);
$meta['layer'] = ($tmp[1] & 0x04) ? (($tmp[1] & 0x02) ? 1 : 2) : (($tmp[1] & 0x02) ? 3 : 0);
$meta['epro'] = ($tmp[1] & 0x01) ? 'no' : 'yes';
// bit rates
$bit_rates = array(
1 => array(
1 => array(0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0),
2 => array(0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0),
3 => array(0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0)
),
2 => array(
1 => array(0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,0),
2 => array(0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0),
3 => array(0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0)
)
);
$i = $meta['mpeg'];
$j = $meta['layer'];
$k = ($tmp[2]>>4);
$meta['bitrate'] = $bit_rates[$i][$j][$k];
// sample rates <采样率>
$sam_rates = array(1=>array(44100,48000,32000,0), 2=>array(22050,24000,16000,0));
$meta['samrate'] = $sam_rates[$i][$k];
$meta["padding"] = ($tmp[2] & 0x02) ? 'on' : 'off';
$meta["private"] = ($tmp[2] & 0x01) ? 'on' : 'off';
// mode & mode_ext
$k = ($tmp[3]>>6);
$channel_modes = array('stereo', 'joint stereo', 'dual channel', 'single channel');
$meta['mode'] = $channel_modes[$k];
$k = (($tmp[3]>>4) & 0x03);
$extend_modes = array('MPG_MD_LR_LR', 'MPG_MD_LR_I', 'MPG_MD_MS_LR', 'MPG_MD_MS_I');
$meta['ext_mode'] = $extend_modes[$k];
$meta['copyright'] = ($tmp[3] & 0x08) ? 'yes' : 'no';
$meta['original'] = ($tmp[3] & 0x04) ? 'yes' : 'no';
$emphasis = array('none', '50/15 microsecs', 'rreserved', 'CCITT J 17');
$k = ($tmp[3] & 0x03);
$meta['emphasis'] = $emphasis[$k];
return $meta;
}
// set v1 info
function _set_v1_info($pa)
{
// ID3v1 (simpled)
$off = -128;
if (!($tmp = $this->head1))
{
$off = 0;
$tmp['id'] = 'TAG';
$tmp['Title'] = $tmp['Artist'] = $tmp['AlbumTitle'] = $tmp['Year'] = $tmp['Description'] = '';
$tmp['Reserved'] = $tmp['Track'] = $tmp['Genre'] = 0;
}
// basic items
$items = array('Title', 'Artist', 'Copyright', 'Description', 'Year', 'AlbumTitle');
foreach ($items as $k)
{
if (isset($pa[$k])) $tmp[$k] = $pa[$k];
}
// genre index
if (isset($pa['Genre']))
{
$g = 0;
foreach ($this->genres as $gtmp)
{
if (!strcasecmp($gtmp, $pa['Genre']))
break;
$g++;
}
$tmp['Genre'] = $g;
}
if (isset($pa['Track'])) $tmp['Track'] = intval($pa['Track']);
// pack the data
$buf = pack('a3a30a30a30a4a28CCC', $tmp['id'], $tmp['Title'], $tmp['Artist'], $tmp['AlbumTitle'],
$tmp['Year'], $tmp['Description'], 0, $tmp['Track'], $tmp['Genre']);
flock($this->fd, LOCK_EX);
fseek($this->fd, $off, SEEK_END);
fwrite($this->fd, $buf, 128);
flock($this->fd, LOCK_UN);
}
// set v2 info
function _set_v2_info($pa)
{
if (!$this->head)
{ // insert ID3
return; // 没有就算了
/**
$tmp = array('id'=>'ID3','ver'=>3,'rev'=>0,'flag'=>0);
$tmp['size'] = -10; // +10 => 0
$this->head = $tmp;
$this->head_buf = '';
$this->head_off = 0;
**/
}
$items = array( 'TCOP'=>'Copyright', 'TPE1'=>'Artist', 'TIT2'=>'Title', 'TRAC'=>'Track',
'TCON'=>'Genre', 'COMM'=>'Description', 'TYER'=>'Year', 'TALB'=>'AlbumTitle');
$head_body = '';
while (true)
{
$buf = $this->_read_head_buf(10);
if (strlen($buf) != 10) break;
$tmp = unpack('a4fid/Nsize/nflag', $buf);
if ($tmp['size'] == 0) break;
$data = $this->_read_head_buf($tmp['size']);
if (($k = $items[$tmp['fid']]) && isset($pa[$k]))
{
// the data should prefix by "\0" [replace]
$data = "\0" . $pa[$k];
unset($pa[$k]);
}
$head_body .= pack('a4Nn', $tmp['fid'], strlen($data), $tmp['flag']) . $data;
}
// reverse the items & set the new tags
$items = array_flip($items);
foreach ($pa as $k => $v)
{
if ($fid = $items[$k])
{
$head_body .= pack('a4Nn', $fid, strlen($v) + 1, 0) . "\0" . $v;
}
}
// new length
$new_len = strlen($head_body) + 10;
$old_len = $this->head['size'] + 10;
if ($new_len < $old_len)
{
$head_body .= str_repeat("\0", $old_len - $new_len);
$new_len = $old_len;
}
// count the size1,2,3,4, no include the header
// 较为变态的算法... :p (28bytes integer)
$size = array();
$nlen = $new_len - 10;
for ($i = 4; $i > 0; $i--)
{
$size[$i] = ($nlen & 0x7f);
$nlen >>= 7;
}
$tmp = $this->head;
//echo "old_len : $old_len new_len: $new_len\n";
$head_buf = pack('a3CCCCCCC', $tmp['id'], $tmp['ver'], $tmp['rev'], $tmp['flag'],
$size[1], $size[2], $size[3], $size[4]);
$head_buf .= $head_body;
$this->_file_save($head_buf, $old_len, $new_len);
}
}
?>