花了不少时间和心思作了这个东西, 使用PHP去读取或修改 MP3或WMA文件的头信息(主要有专辑,歌名,歌手等)
其实网上搜索有不少 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);
}
}
?>
其实网上搜索有不少 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);
}
}
?>
在许多应用软件运行时都带有命令行参数,其实这些命令行参数在C语言编写的程序中也可以实现,灵活地运用命令行参数进行处理可以有效地提高程序的运行效率,收到事半功倍的效果。
C语言中有关命令行参数涉及到程序的主函数main(int argc,char *argv[]这样两个参数,其中,int argc表示命令行参数的个数(包括可执行程序名本身),char *argv[]表示每个参数的具体内容,argv[0]为命令行中可执行程序名本身,argv[1]为命令行中第二个参数的内容,依次类推。如下例输出命令行参数的个数及参数的内容:
main (int argc,char *argv[],
{int I;
printf("\n命令行中可执行文件名为:%s",argv[0]);
printf("\n总共有%d个参数:",argc);
I=0;
while(argc>=1)
{printf(″%s ",argv[I++]);
argc--;}
}
命令行参数用的最多还是在诸如DIR A:等之类带有盘符、路径或文件名这样的命令行中,所以说灵活处理这一类参数才能有效地提高程序的运行效果。譬如DIR命令,其后可以是盘符,可以是路径,也可以是文件名,如何区分这一参数呢?请看下例(此程序模拟DIR命令,程序要求在命令行输入一个参数:盘符或路径或文件名,若无参数或参数多于一个都将取默认的参数“*.*”)。
\*--------------------
功能:模拟DIR命令进行处理命令行参数
--------------------*/
#include
#include
#include
#inchlude
int j,num=0;
char ss[20],path[50],path2[50];
void main (int argc,char *argv[])
{
struct ffblk f;
int done;
if(argc==2) /*取命令行参数到数组中*/
strcpy(ss,argv[1]);
else
strcpy(ss,″*.*″); /*给数组赋值缺省参数*/
if (((ss[strlen(ss)-1]==′\\′||((ss[strlen(ss)-1]==':'))
strcat(ss,″*.*″); /*若参数为路径或盘符,则加上″*.*″ */
getcwd(path1,50); /*取当前路径*/
if (chdir(ss)==0) /*判断参数是否为路径*/
strcat(ss,"\\*.*"); /*若路径末没有带"\",则加上"*.*" */
chdir(path1); /*恢复原来路径*/
strcpy(path2,ss);
for(j=strlen(path2);j>0;j--)/*提取参数中的路径到path2 */
{if((path2[j]=='\\'))||(path2[j]==':')){
path2[j+1]='\0';
goto senull;}
}
path2[0]='\0';
senull:
if(strlen(path2)==0) /* 若给出的参数中没带路径,则取当前路径*/
strcpy(path2,path1);
printf("\n**模拟DIR**\n 命令目录路径%s",path2);
done=findfirst(ss,&f,55); /*查找第一个配匹的文件*/
j=1;
while(!done)
{if (f.ff_attrib!=0x10) /* 若文件属性不是目录 */
printf("\n %15s %20ld",f.ff_name,f.ff_fsize);
else
printf("\n &11s ",f.ff_name);
num++;
j++;
if(j==23)
printf("\n --------More (按任意键继续)----");
getch();
j=0;
printf(″\n (目录路径%s)″,path2);}
done=findnext(&f); /*查找下一个配匹的文件*/
}
printf(″\n 当前目录中总共有%d个文件.\n″,num);
C语言中有关命令行参数涉及到程序的主函数main(int argc,char *argv[]这样两个参数,其中,int argc表示命令行参数的个数(包括可执行程序名本身),char *argv[]表示每个参数的具体内容,argv[0]为命令行中可执行程序名本身,argv[1]为命令行中第二个参数的内容,依次类推。如下例输出命令行参数的个数及参数的内容:
main (int argc,char *argv[],
{int I;
printf("\n命令行中可执行文件名为:%s",argv[0]);
printf("\n总共有%d个参数:",argc);
I=0;
while(argc>=1)
{printf(″%s ",argv[I++]);
argc--;}
}
命令行参数用的最多还是在诸如DIR A:等之类带有盘符、路径或文件名这样的命令行中,所以说灵活处理这一类参数才能有效地提高程序的运行效果。譬如DIR命令,其后可以是盘符,可以是路径,也可以是文件名,如何区分这一参数呢?请看下例(此程序模拟DIR命令,程序要求在命令行输入一个参数:盘符或路径或文件名,若无参数或参数多于一个都将取默认的参数“*.*”)。
\*--------------------
功能:模拟DIR命令进行处理命令行参数
--------------------*/
#include
#include
#include
#inchlude
int j,num=0;
char ss[20],path[50],path2[50];
void main (int argc,char *argv[])
{
struct ffblk f;
int done;
if(argc==2) /*取命令行参数到数组中*/
strcpy(ss,argv[1]);
else
strcpy(ss,″*.*″); /*给数组赋值缺省参数*/
if (((ss[strlen(ss)-1]==′\\′||((ss[strlen(ss)-1]==':'))
strcat(ss,″*.*″); /*若参数为路径或盘符,则加上″*.*″ */
getcwd(path1,50); /*取当前路径*/
if (chdir(ss)==0) /*判断参数是否为路径*/
strcat(ss,"\\*.*"); /*若路径末没有带"\",则加上"*.*" */
chdir(path1); /*恢复原来路径*/
strcpy(path2,ss);
for(j=strlen(path2);j>0;j--)/*提取参数中的路径到path2 */
{if((path2[j]=='\\'))||(path2[j]==':')){
path2[j+1]='\0';
goto senull;}
}
path2[0]='\0';
senull:
if(strlen(path2)==0) /* 若给出的参数中没带路径,则取当前路径*/
strcpy(path2,path1);
printf("\n**模拟DIR**\n 命令目录路径%s",path2);
done=findfirst(ss,&f,55); /*查找第一个配匹的文件*/
j=1;
while(!done)
{if (f.ff_attrib!=0x10) /* 若文件属性不是目录 */
printf("\n %15s %20ld",f.ff_name,f.ff_fsize);
else
printf("\n &11s ",f.ff_name);
num++;
j++;
if(j==23)
printf("\n --------More (按任意键继续)----");
getch();
j=0;
printf(″\n (目录路径%s)″,path2);}
done=findnext(&f); /*查找下一个配匹的文件*/
}
printf(″\n 当前目录中总共有%d个文件.\n″,num);
新婚之夜,新郎手抚新娘两腿之间问:"这是什么?"新娘答:"党!"新郎说:"我想入党,行不?"新娘道:"你迫切要求入党的心情我懂,但正式入党还需符合以下条件:1、只要你过得硬,党的大门随时为你敞开;2、党的宗旨是:党指挥枪!3、入了我的党,就不能入别的党;4、对党要绝对忠诚,并誓死捍卫党的纯洁;5、不许入党前干劲十足,入党后萎靡不振;6、要与时俱进大胆创新,全方位多角度促进党内和谐;7、必须每月按时足额交纳党费;8、要勇往直前,不怕牺牲,甘愿为党流尽最后一滴血,永不叛党!以上八条党性要求,你能做到吗?"新郎激动地说:"我能!党叫咋干就咋干,时刻听从党召唤
今天上班发现phpmyadmin出现:出现空白页面或无法载入 mysql 扩展。
查了一下原来是php.ini配置有问题:
修改如下:
1. extension_dir = 和PHP实际的ext目录不一致。(默认当前目录)
2. 没有把PHP目录和ext目录添加到环境变量中。(修改path)
3. extension=php_mysql.dll等前的;注释没去掉。(去掉;)
4. Zend安装目录和php.ini中Zend指定的目录不一致。
把上面几种情况检查一下,若还不能解决,请使用其他方法
查了一下原来是php.ini配置有问题:
修改如下:
1. extension_dir = 和PHP实际的ext目录不一致。(默认当前目录)
2. 没有把PHP目录和ext目录添加到环境变量中。(修改path)
3. extension=php_mysql.dll等前的;注释没去掉。(去掉;)
4. Zend安装目录和php.ini中Zend指定的目录不一致。
把上面几种情况检查一下,若还不能解决,请使用其他方法
索尼V700采用头戴密封式设计,左右耳机是可以旋转并反转的,耳罩外壳是很COOL的磨砂银白色.并采用了Supra-aural设计,能轻松舒适地戴在耳朵上,创造最佳音响效果。而V700更具有令人震憾的5HZ~30000HZ频率反应,这可是我见过这么多耳机中最历害的(E888也不过是8HZ~27000HZ),因此V700无论是高音还是低音都绝对是NO.1的,而V700最大输出功率更有3000mW,小转大转换插头当然也随机附送啦!
最大输出功率更有3000mW.低音强劲,很有力度,而且非常松,余响效果非常好,一点都不会生硬.是那种动态宽广的重低音效果,感觉不是在听耳机,而是在听音响,而高音部分则非常清晰,绝不刺耳。国内外的DJ高手的耳机配备基本都是V700。
类型:密闭型、动态形
驱动单元:500
磁体:钕
阻抗:24欧
最大灵敏度:107dB/mW
最大输出功率:3000mW
频率响应:5-30,000Hz
连接线:螺旋型高纯度无氧铜
SONY MDR-Z700DJ众所周知的SONY监听级耳机,音质绝对发烧,让您一戴上就不想放下来。别看一个小小的耳机才几百元,但它给你带来的音响感受绝对不输上几千元的音箱,如果您囊中羞涩,又想体会什么叫hifi品质的话,何不买一款SONY MDR-Z700头戴式监听级耳机呢?Z700线很长接电脑、电视、音响功放都是非常合适的。不打扰别人,独自享受!您就一个人偷着乐吧。
(请买家注意z700不能直接用在电脑ac97声卡上,因为97声卡仅仅是微弱的信号输出,听小耳塞还行,但无法推动z700这类大耳机,如要用在电脑上最好是独立声卡,或有功率放大的声卡,sblive这样的声卡已经是绰绰有余了)
作为最受专业DJ用家推荐的MDR-Z700是SONY的高价位DJ专用耳机,Z700采用头戴密封式设计,银白色外观,耳机部分采用50mm的超薄喇叭单体,耳桶部分是可以旋转并反向收合的,耳罩外壳是很COOL的磨砂银白色。并采用了Supra-aural设计,加宽的头带便于佩带;能轻松舒适地戴在耳朵上,其厚度及柔软度非常适中的皮垫在长期配带的过程中非常舒适。创造最佳音响效果。可以折叠以缩小体积,方便外出携带或收藏存放。
而Z700更具有令人震憾的5HZ~30000HZ频率反应,这可是我见过这么多耳机中最历害的(E888也不过是8HZ~27000HZ),因此Z700无论是高音还是低音都绝对是NO.1的,小转大转换插头当然也随机附送啦!
最大输出功率更有3000mW.低音强劲,很有力度,而且非常松,余响效果非常好,一点都不会生硬.是那种动态宽广的重低音效果,感觉不是在听耳机,而是在听音响,而高音部分则非常清晰,绝不刺耳。国内外的DJ高手的耳机配备基本都是Z700。
(请买家注意z700不能直接用在电脑ac97声卡上,因为97声卡仅仅是微弱的信号输出,听小耳塞还行,但无法推动z700这类大耳机,如要用在电脑上最好是独立声卡,或有功率放大的声卡,sblive这样的声卡已经是绰绰有余了)
我的声卡好象功率还不行,妈的就只能听到一般的声音 ,重低音乐不行,奶奶的....
俺这人平时很少看电视,感觉太假!
演来演去的,总是熟悉得不能再熟悉的几张面孔,只是角色名字不停的更换而已。他们的演技也就那样了,当初的美女,也架不住总看呀!男星,就那几根葱,除了脸皮不断厚实外,也没什么可以看的。人家这叫“成熟”起来了!
我本来要一心在网上混的,这里才是自由的世界呢!干啥都行,说啥都行。何况还真有几个网友呢,在一起神侃一顿,不是有趣的多?但条件不允许,有时还得暂时离开一会儿网络。那天就是因为要抱可儿,不能上网,万般无奈,便也坐在沙发上看那无聊的电视。
电视的名字是《人在旅途》,播放的是第18集。至于这之前咋回事儿,咱不知道。这段电视的大意是:一个叫虎子的人,是个很横的主儿,因为别人摸了一下他女友,他将别人打伤了,判3年徒刑。他的女友雪,耐不住寂寞,和一个老板好上了。老虎刑满释放后,偷偷的回来了,想给雪儿一个惊喜!偏遇到那老板和雪正偷情呢。惊喜是没有了,变成了捉奸!那男人走后,老虎越想越不对劲儿,咽不下这口气。那意思是:要杀了那鸟人!
由此,我就有个感想,这偷情,实在不是什么美事!
当初男人上女人床,或将女人唬弄到上自己的床,也许是快活的。男人,有了情欲的释放空间,尽着自己的性子来发泄;女人,也品尝出另种滋味。但天下没有不散的筵席呀,折腾完之后呢?女人要面对自己的老公,男人要面对自己的老婆。设若是玩个一夜情,也就罢了,裤子一提,彼此再没联系,也还是偷情成功。男人当作做了一次义务劳动,女人当作被狗舔了一口。这种情况,上床容易,下床也不难。但若是双方熟悉,并经过若干次的努力,才勾搭上手的,那怎么会舍得就此罢休呢?这美酒才品尝一口呢,味道好极了,还得接着喝才是呀!所以既然偷情了,往往就不是一夜情能了结的!
双方为了达到肌肤相亲,都是积极地向铁人王进喜同志学习:有条件要上,没有条件创造条件也要上!彼此的朝思暮想,比恋人相思还强烈!只要离开自己伴侣的眼睛,马上就紧急集合!来的也直接:各自脱自己的衣服,干活儿!这次干完,还期待着下次。这样接二连三的干下去,保不正偏偏哪天老公(老婆)回家拿个什么东西,无意中就捉了奸!这时候,不是难堪的问题了,要面临家将不家的问题了!试问:谁能忍受后院起火的屈辱呢?一般而言,就是后院冒烟,那都要拿着灭火器仔细喷洒一通,这后院的火呼呼的烧,谁能甘心呀?阅读全文
演来演去的,总是熟悉得不能再熟悉的几张面孔,只是角色名字不停的更换而已。他们的演技也就那样了,当初的美女,也架不住总看呀!男星,就那几根葱,除了脸皮不断厚实外,也没什么可以看的。人家这叫“成熟”起来了!
我本来要一心在网上混的,这里才是自由的世界呢!干啥都行,说啥都行。何况还真有几个网友呢,在一起神侃一顿,不是有趣的多?但条件不允许,有时还得暂时离开一会儿网络。那天就是因为要抱可儿,不能上网,万般无奈,便也坐在沙发上看那无聊的电视。
电视的名字是《人在旅途》,播放的是第18集。至于这之前咋回事儿,咱不知道。这段电视的大意是:一个叫虎子的人,是个很横的主儿,因为别人摸了一下他女友,他将别人打伤了,判3年徒刑。他的女友雪,耐不住寂寞,和一个老板好上了。老虎刑满释放后,偷偷的回来了,想给雪儿一个惊喜!偏遇到那老板和雪正偷情呢。惊喜是没有了,变成了捉奸!那男人走后,老虎越想越不对劲儿,咽不下这口气。那意思是:要杀了那鸟人!
由此,我就有个感想,这偷情,实在不是什么美事!
当初男人上女人床,或将女人唬弄到上自己的床,也许是快活的。男人,有了情欲的释放空间,尽着自己的性子来发泄;女人,也品尝出另种滋味。但天下没有不散的筵席呀,折腾完之后呢?女人要面对自己的老公,男人要面对自己的老婆。设若是玩个一夜情,也就罢了,裤子一提,彼此再没联系,也还是偷情成功。男人当作做了一次义务劳动,女人当作被狗舔了一口。这种情况,上床容易,下床也不难。但若是双方熟悉,并经过若干次的努力,才勾搭上手的,那怎么会舍得就此罢休呢?这美酒才品尝一口呢,味道好极了,还得接着喝才是呀!所以既然偷情了,往往就不是一夜情能了结的!
双方为了达到肌肤相亲,都是积极地向铁人王进喜同志学习:有条件要上,没有条件创造条件也要上!彼此的朝思暮想,比恋人相思还强烈!只要离开自己伴侣的眼睛,马上就紧急集合!来的也直接:各自脱自己的衣服,干活儿!这次干完,还期待着下次。这样接二连三的干下去,保不正偏偏哪天老公(老婆)回家拿个什么东西,无意中就捉了奸!这时候,不是难堪的问题了,要面临家将不家的问题了!试问:谁能忍受后院起火的屈辱呢?一般而言,就是后院冒烟,那都要拿着灭火器仔细喷洒一通,这后院的火呼呼的烧,谁能甘心呀?阅读全文
1、父子二人经过五星级饭店门口,看到一辆十分豪华的进口轿车。儿子不屑地对他的父亲说:「坐这种车的人,肚子里一定没有学问!」父亲则轻描淡写地回答:「说这种话的人,口袋里一定没有钱!」 (注:你对事情的看法,是不是也反映出你内心真正的态度?)
2、晚饭后,母亲和女儿一块儿洗碗盘,父亲和儿子在客厅看电视。突然,厨房里传来打破盘子的响声,然后一片沉寂。是儿子望着他父亲,说道:「一定是妈妈打破的。」「你怎么知道?」「她没有骂人。」
(注:我们习惯以不同的标准来看人看己,以致往往是责人以严,待己以宽。)
3、有两个台湾观光团到***伊豆半岛旅游,路况很坏,到处都是坑洞。其中一位导游连声抱歉,说路面简直像麻子一样。说而另一个导游却诗意盎然地对游客说:诸位先生女士,我们现在走的这条道路,正是赫赫有名的伊豆迷人酒窝大道。」
(注:虽是同样的情况,然而不同的意念,就会产生不同的态度。思想是何等奇妙的事,如何去想,决定权在你。)
4、同样是小学三年级的学生,在作文中说他们将来的志愿是当小丑。中国的老师斥之为:「胸无大志,孺子不可教也!」带外国的老师则会说:「愿你把欢笑带给全世界!」
(注:身为长辈的我们,不但容易要求多于鼓励,更狭窄的界定了成功的定义。)
5、在故宫博物院中,有一个太太不耐烦地对她先生说:「我说你为甚么走得这么慢。原来你老是停下来看这些东西。」
(注:有人只知道在人生的道路上狂奔,结果失去了观看两旁美丽花朵的机会。)
6、妻子正在厨房炒菜。丈夫在她旁边一直唠叨不停:慢些。小心!火太大了。赶快把鱼翻过来。快铲起来,油放太多了!把豆腐整平一下!「哎?」妻子***口而出,「我懂得怎样炒菜。」「你当然懂,太太,」丈夫平静地答道:「我只是要让你知道,我在开车时,你在旁边喋喋不休,我的感觉如何。」
注:学会体谅他人并不困难,只要你愿意认真地站在对方的角度和立场看问题。)
7、理由充份
一辆载满乘客的公共汽车沿着下坡路快速前进着,有一个人後面紧紧地追赶着这辆车子。一个乘客从车窗中伸出头来对追车子的人说:“老兄!算啦,你追不上的!”“我必须追上它,”这人气喘吁吁地说:“我是这辆车的司机!”
(注:有些人必须非常认真努力,因为不这样的话,後果就十分悲惨了!然而也正因为必须全力以赴,潜在的本能和不为人知的特质终将充份展现出来。)
8、原来如此
甲:「新搬来的邻居好可恶,昨天晚上三更半夜、夜深人静之时然跑来猛按我家的门铃。」乙:「的确可恶!你有没有马上报警?」甲:「没有。我当他们是疯子,继续吹我的小喇叭。」
(事出必有因,如果能先看到自己的不是,答案就会不一样在你面对冲突和争执时,先想一想是否心中有亏,或许很快就能释怀了。)
9、误会
某日,张三在山间小路开车,正当他悠哉地欣赏美丽风景时,突然迎面开来一辆货车,而且满囗黑牙的司机还摇下窗户对他大骂一声:“猪!”
张三越想越纳闷,也越想越气,於是他也摇下车窗回头大骂:“你才是猪!”
才刚骂完,他便迎头撞上一群过马路的猪。
(不要错误的诠释别人的好意,那只会让自己吃亏,并且使别人受辱。在不明所以之前,先学会按捺情绪,耐心观察,以免事後生发悔意。)
10、後生可畏
小男孩问爸爸:“是不是做父亲的总比做儿子的知道得多?”
爸爸回答:“当然啦!”
小男孩问:“电灯是谁发明的?”
爸爸:“是爱迪生。”
小男孩又问:“那爱迪生的爸爸怎麽没有发明电灯?”
(很奇怪,喜欢倚老卖老的人,特别容易栽跟斗。权威往往只是一个经不起考验的空壳子,尤其在现今这个多元开放的时代。)
11、不必紧张
小明洗澡时不小心吞下一小块肥皂,他的妈妈慌慌张张地打电话向家庭医生求助。医生说:“我现在还有几个病人在,可能要半小时後才能赶过去。”
小明妈妈说:“在你来之前,我该做甚麽?”
医生说:“给小明喝一杯白开水,然後用力跳一跳,你就可以让小明用嘴巴吹泡泡消磨时间了。”
(take it easy,放轻松放轻松些,生活何必太紧张?事情既然已经发生了,何不坦然自在的面对。担心不如宽心,穷紧张不如穷开心。)
12、钥匙
一把坚实的大锁挂在大门上,一根铁杆费了九牛二虎之力,还是无法将它撬开。钥匙来了,他瘦小的身子钻进锁孔,只轻轻一转,大锁就“啪”地一声打开了。
铁杆奇怪地问:“为什麽我费了那麽大力气也打不开,而你却轻而易举地就把它打开了呢?”
钥匙说:“因为我最了解他的心。”
(每个人的心,都像上了锁的大门,任你再粗的铁棒也撬不开)
2、晚饭后,母亲和女儿一块儿洗碗盘,父亲和儿子在客厅看电视。突然,厨房里传来打破盘子的响声,然后一片沉寂。是儿子望着他父亲,说道:「一定是妈妈打破的。」「你怎么知道?」「她没有骂人。」
(注:我们习惯以不同的标准来看人看己,以致往往是责人以严,待己以宽。)
3、有两个台湾观光团到***伊豆半岛旅游,路况很坏,到处都是坑洞。其中一位导游连声抱歉,说路面简直像麻子一样。说而另一个导游却诗意盎然地对游客说:诸位先生女士,我们现在走的这条道路,正是赫赫有名的伊豆迷人酒窝大道。」
(注:虽是同样的情况,然而不同的意念,就会产生不同的态度。思想是何等奇妙的事,如何去想,决定权在你。)
4、同样是小学三年级的学生,在作文中说他们将来的志愿是当小丑。中国的老师斥之为:「胸无大志,孺子不可教也!」带外国的老师则会说:「愿你把欢笑带给全世界!」
(注:身为长辈的我们,不但容易要求多于鼓励,更狭窄的界定了成功的定义。)
5、在故宫博物院中,有一个太太不耐烦地对她先生说:「我说你为甚么走得这么慢。原来你老是停下来看这些东西。」
(注:有人只知道在人生的道路上狂奔,结果失去了观看两旁美丽花朵的机会。)
6、妻子正在厨房炒菜。丈夫在她旁边一直唠叨不停:慢些。小心!火太大了。赶快把鱼翻过来。快铲起来,油放太多了!把豆腐整平一下!「哎?」妻子***口而出,「我懂得怎样炒菜。」「你当然懂,太太,」丈夫平静地答道:「我只是要让你知道,我在开车时,你在旁边喋喋不休,我的感觉如何。」
注:学会体谅他人并不困难,只要你愿意认真地站在对方的角度和立场看问题。)
7、理由充份
一辆载满乘客的公共汽车沿着下坡路快速前进着,有一个人後面紧紧地追赶着这辆车子。一个乘客从车窗中伸出头来对追车子的人说:“老兄!算啦,你追不上的!”“我必须追上它,”这人气喘吁吁地说:“我是这辆车的司机!”
(注:有些人必须非常认真努力,因为不这样的话,後果就十分悲惨了!然而也正因为必须全力以赴,潜在的本能和不为人知的特质终将充份展现出来。)
8、原来如此
甲:「新搬来的邻居好可恶,昨天晚上三更半夜、夜深人静之时然跑来猛按我家的门铃。」乙:「的确可恶!你有没有马上报警?」甲:「没有。我当他们是疯子,继续吹我的小喇叭。」
(事出必有因,如果能先看到自己的不是,答案就会不一样在你面对冲突和争执时,先想一想是否心中有亏,或许很快就能释怀了。)
9、误会
某日,张三在山间小路开车,正当他悠哉地欣赏美丽风景时,突然迎面开来一辆货车,而且满囗黑牙的司机还摇下窗户对他大骂一声:“猪!”
张三越想越纳闷,也越想越气,於是他也摇下车窗回头大骂:“你才是猪!”
才刚骂完,他便迎头撞上一群过马路的猪。
(不要错误的诠释别人的好意,那只会让自己吃亏,并且使别人受辱。在不明所以之前,先学会按捺情绪,耐心观察,以免事後生发悔意。)
10、後生可畏
小男孩问爸爸:“是不是做父亲的总比做儿子的知道得多?”
爸爸回答:“当然啦!”
小男孩问:“电灯是谁发明的?”
爸爸:“是爱迪生。”
小男孩又问:“那爱迪生的爸爸怎麽没有发明电灯?”
(很奇怪,喜欢倚老卖老的人,特别容易栽跟斗。权威往往只是一个经不起考验的空壳子,尤其在现今这个多元开放的时代。)
11、不必紧张
小明洗澡时不小心吞下一小块肥皂,他的妈妈慌慌张张地打电话向家庭医生求助。医生说:“我现在还有几个病人在,可能要半小时後才能赶过去。”
小明妈妈说:“在你来之前,我该做甚麽?”
医生说:“给小明喝一杯白开水,然後用力跳一跳,你就可以让小明用嘴巴吹泡泡消磨时间了。”
(take it easy,放轻松放轻松些,生活何必太紧张?事情既然已经发生了,何不坦然自在的面对。担心不如宽心,穷紧张不如穷开心。)
12、钥匙
一把坚实的大锁挂在大门上,一根铁杆费了九牛二虎之力,还是无法将它撬开。钥匙来了,他瘦小的身子钻进锁孔,只轻轻一转,大锁就“啪”地一声打开了。
铁杆奇怪地问:“为什麽我费了那麽大力气也打不开,而你却轻而易举地就把它打开了呢?”
钥匙说:“因为我最了解他的心。”
(每个人的心,都像上了锁的大门,任你再粗的铁棒也撬不开)
经典爱情诗
婚前
女:你原先有过女朋友?
男:十年生死两茫茫,不思量,自难忘。
女:死了?怎么死的?
男:山天陵,江水为竭,冬雷阵阵夏雨雪。
女:喔,是天灾。那这些年你怎么过来的?
男:满面尘灰烟火色,两手苍苍十指黑。
女;唉,不容易。那么你看见我的第一感觉是什么?
男:忽如-夜春风来,千树万树梨花开。
女:(红着脸)有那么好?
男:糟粕所传非粹美,丹青难写是精神。
女:马屁精--你有理想吗?
男:他年若遂凌云志,敢笑黄巢不丈夫。
女:你……对爱情的看法呢?
男:只在此山中,云深不知处。
女:那你喜欢读书吗?
男:军书十二卷,卷卷有爷名!
女:这牛吹大了吧?你那么大才华,怎么还独身?
男:小姑未嫁身如寄,莲子心多苦自知。
女:(笑)假如,我是说假如,我答应嫁给你,你打算怎样待我?
男:一片冰心在玉壶!
女:你保证不会对别的女人动心?
男:波澜誓不起,妾心古井水。
女:暂且信你一回,不过,我正打算去美国念书,你能等我吗?
男:此去经年,应是良辰美景虚设。
女:不过……
男:独自凭栏,无限江山,别时容易见时难!
女:但是…….
男:望夫处,江悠悠,化为石,不回头!
女;好了好了,怕了你………
婚后
女:结婚那么久,你还在想你原先妁女朋友?
男:曾经沧海难为水,除却巫山不是云。
女:那为什么当年还和我结婚?
男:梦里不知身是客,一晌贪欢。
女:太过分了吧。我们好歹是夫妻。
男:夫妻本是同林鸟,大难临头各自飞。
女:那我们这段婚姻,你怎么看?
男:醒来几向楚巾看,梦觉尚心寒!
女:有那么惨吗?你不是说对我的第一印象……
男:美女如花满春殿,身边惟有鹧鸪飞。
女:不是这么说的吧,难道,你竟然……
男:昔日龌龊不足夸,今朝放荡思无涯。
女:一直以来朋友写信告诉我我都不相信,没想到竟是真的!
男:纸上得来终觉浅,绝知此事要躬行。
女:你原先的理想都到哪儿去了?
男:且把浮名,换了斟低唱。
女:(泪眼朦胧)你,你不是答应一片冰心的吗?
男:不忍见此物,焚之已成灰。
女:你就不怕亲朋耻笑,后世唾骂?
男:宁可抱香枝头死,何曾吹落北风中。
女:我要不同意分手呢?
男:分手尚且为兄弟,何必非做骨肉亲。
女:好,够绝
婚前
女:你原先有过女朋友?
男:十年生死两茫茫,不思量,自难忘。
女:死了?怎么死的?
男:山天陵,江水为竭,冬雷阵阵夏雨雪。
女:喔,是天灾。那这些年你怎么过来的?
男:满面尘灰烟火色,两手苍苍十指黑。
女;唉,不容易。那么你看见我的第一感觉是什么?
男:忽如-夜春风来,千树万树梨花开。
女:(红着脸)有那么好?
男:糟粕所传非粹美,丹青难写是精神。
女:马屁精--你有理想吗?
男:他年若遂凌云志,敢笑黄巢不丈夫。
女:你……对爱情的看法呢?
男:只在此山中,云深不知处。
女:那你喜欢读书吗?
男:军书十二卷,卷卷有爷名!
女:这牛吹大了吧?你那么大才华,怎么还独身?
男:小姑未嫁身如寄,莲子心多苦自知。
女:(笑)假如,我是说假如,我答应嫁给你,你打算怎样待我?
男:一片冰心在玉壶!
女:你保证不会对别的女人动心?
男:波澜誓不起,妾心古井水。
女:暂且信你一回,不过,我正打算去美国念书,你能等我吗?
男:此去经年,应是良辰美景虚设。
女:不过……
男:独自凭栏,无限江山,别时容易见时难!
女:但是…….
男:望夫处,江悠悠,化为石,不回头!
女;好了好了,怕了你………
婚后
女:结婚那么久,你还在想你原先妁女朋友?
男:曾经沧海难为水,除却巫山不是云。
女:那为什么当年还和我结婚?
男:梦里不知身是客,一晌贪欢。
女:太过分了吧。我们好歹是夫妻。
男:夫妻本是同林鸟,大难临头各自飞。
女:那我们这段婚姻,你怎么看?
男:醒来几向楚巾看,梦觉尚心寒!
女:有那么惨吗?你不是说对我的第一印象……
男:美女如花满春殿,身边惟有鹧鸪飞。
女:不是这么说的吧,难道,你竟然……
男:昔日龌龊不足夸,今朝放荡思无涯。
女:一直以来朋友写信告诉我我都不相信,没想到竟是真的!
男:纸上得来终觉浅,绝知此事要躬行。
女:你原先的理想都到哪儿去了?
男:且把浮名,换了斟低唱。
女:(泪眼朦胧)你,你不是答应一片冰心的吗?
男:不忍见此物,焚之已成灰。
女:你就不怕亲朋耻笑,后世唾骂?
男:宁可抱香枝头死,何曾吹落北风中。
女:我要不同意分手呢?
男:分手尚且为兄弟,何必非做骨肉亲。
女:好,够绝
这个网址破解很快的,对MD5的破解。。。。
http://www.tmto.org/?category=main&page=search_md5
http://www.tmto.org/?category=main&page=search_md5
$mysql_server_name='localhost';
$mysql_username='root';
$mysql_password='123456';
$mysql_database='flv_demo';
$conn=mysql_connect($mysql_server_name,$mysql_username,$mysql_password,$mysql_database);
$sql='CREATE DATABASE mycounter DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci;
';
mysql_query($sql);
$sql='CREATE TABLE `counter` (`id` INT(255) UNSIGNED NOT NULL AUTO_INCREMENT ,`count` INT(255) UNSIGNED NOT NULL DEFAULT 0,PRIMARY KEY ( `id` ) ) TYPE = innodb;';
mysql_select_db($mysql_database,$conn);
$result=mysql_query($sql);
//echo $sql;
mysql_close($conn);
echo "Hello!数据库mycounter已经成功建立!";
?>
$mysql_username='root';
$mysql_password='123456';
$mysql_database='flv_demo';
$conn=mysql_connect($mysql_server_name,$mysql_username,$mysql_password,$mysql_database);
$sql='CREATE DATABASE mycounter DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci;
';
mysql_query($sql);
$sql='CREATE TABLE `counter` (`id` INT(255) UNSIGNED NOT NULL AUTO_INCREMENT ,`count` INT(255) UNSIGNED NOT NULL DEFAULT 0,PRIMARY KEY ( `id` ) ) TYPE = innodb;';
mysql_select_db($mysql_database,$conn);
$result=mysql_query($sql);
//echo $sql;
mysql_close($conn);
echo "Hello!数据库mycounter已经成功建立!";
?>
一篇经典的文章----面向对象思想----不看后悔!
前言:
整理这份资料的目的是为了帮助朋友们能够更直观的理解面向对象的编程。让后来者能够少走一些弯路。但其中不免有许多漏洞及错误,也还请前辈提出宝贵的更改意见,毕竟交流会让我们不断的进步。
技术是日新月异的,他不会等待你的成长。技术要拿出来于别人交流,自己学是自己主观意识上的理解,有对有错!交流会让进步变得更快。我认为如果计算机的体系结构不发生革命性的变化,我们现在所应用的程序语言也就百变不离奇踪了!学编程学的是什么?思想!精通一门编程语言(最好是面向对象的语言)后再去搞其他的编程语言,你会发现过程是如此的行云流水!为什么?你已经把编程的思想掌握了,再去学其他的,无非是学习一种新的语法格式了。
我在这里并不是和你讨论怎么去用C++或JAVA,也不是和你讨论怎么去学他们,我要和你讨论的是怎么去理解面向对象。其中主要会涉及到“类、对象、继承、属性、方法、静态、重载、隐藏、重构、声明、定义、初始化、赋值等”其中有许多相关技术我只会一代而过,让你有一种到此一游的意味我就达到目的了,而更详细的技术内幕,就请参考其他相关书籍而深入研究吧!因为我只是在和你探讨如何去更好的理解面向对象!
如何去提高效率?重复使用资源,把别人的东西拿来就用。这是很不错的主意!而对于你来说,最大的资源就是信心以及积极性!好,打起精神来,让我们一同到面向对象的编程中去寻幽访胜吧!
注:文章中所有程序实例我都使用JAVA写的,当然在C++中也就大同小异了了,不同的地方我会指出!
注:文章中的正文文字用黑色,说明文字用蓝色,强调文字用橙色,批改文字用红色!
正文:
1.基本概念:
1.1 类与对象的初探
要我说,无论是面向过程的语言也好,面向对象的语言也罢,我首先要给他讲的都是类和对象!--------“这个世界是由什么组成的?”这个问题如果让不同的人来回答会得到不同的答案。如果是一个化学家,他也许会告诉你“还用问嘛?这个世界是由分子、原子、离子等等的化学物质组成的”。如果是一个画家呢?他也许会告诉你,“这个世界是由不同的颜色所组成的”。……呵呵,众说纷纭吧!但如果让一个分类学家来考虑问题就有趣的多了,他会告诉你“这个世界是由不同类型的物与事所构成的”好!作为面向对象的程序员来说,我们要站在分类学家的角度去考虑问题!是的,这个世界是由动物、植物等组成的。动物又分为单细胞动物、多细胞动物、哺乳动物等等,哺乳动物又分为人、大象、老虎……就这样的分下去了!
现在,站在抽象的角度,我们给“类”下个定义吧!我的意思是,站在抽象的角度,你回答我“什么是人类?”首先让我们来看看人类所具有的一些特征,这个特征包括属性(一些参数,数值)以及方法(一些行为,他能干什么!)。每个人都有身高、体重、年龄、血型等等一些属性。人会劳动、人都会直立行走、人都会用自己的头脑去创造工具等等这些方法!人之所以能区别于其它类型的动物,是因为每个人都具有人这个群体的属性与方法。“人类”只是一个抽象的概念,它仅仅是一个概念,它是不存在的实体!但是所有具备“人类”这个群体的属性与方法的对象都叫人!这个对象“人”是实际存在的实体!每个人都是人这个群体的一个对象。老虎为什么不是人?因为它不具备人这个群体的属性与方法,老虎不会直立行走,不会使用工具等等!所以说老虎不是人!
由此可见-------类描述了一组有相同特性(属性)和相同行为(方法)的对象。在程序中,类实际上就是数据类型!例如:整数,小数等等。整数也有一组特性和行为。面向过程的语言与面相对象的语言的区别就在于,面向过程的语言不允许程序员自己定义数据类型,而只能使用程序中内置的数据类型!而为了模拟真实世界,为了更好的解决问题,往往我们需要创建解决问题所必需的数据类型!面向对象编程为我们提供了解决方案。
1.2 内置数据类型与函数:
计算机程序在存储数据时必须跟踪3个基本属性为:
1. 信息存储在何处;
2. 存储的值是多少;
3. 存储的信息是什么类型的;
让我们来看看编程语言的内置数据类型都有哪些!(呵呵,这个不大好说,因为每门语言都有自己独特的数据类型,但这毕竟是少数,比如在JAVA中有byte类型的数据,而在C++中就没有,希望你能举一反三!)比如整数”int ”,浮点类型的数据”float”!字符串”String”,以及数组还有结构体等等。然而在写程序的时候,根据需要我们会创建一个类型的变量或常量,例如:由于我们需要创建一个整形的变量i为5,我们就可以这样做,int i = 5;而根据需要我很有可能改变i的值,也就是从新给它赋值,比如让它等与6,就可以在所需的地方改成i = 6;由此我们知道,在“值”上可以发生变化的量就叫变量。不会发生变化的量就叫做常量了,在C++中用count关键字来声明,而在JAVA中则使用final关键字来声明。由于不同语言的声明格式不一样,这里就不做一一介绍了,详细的内容清查阅相关书籍!阅读全文
前言:
整理这份资料的目的是为了帮助朋友们能够更直观的理解面向对象的编程。让后来者能够少走一些弯路。但其中不免有许多漏洞及错误,也还请前辈提出宝贵的更改意见,毕竟交流会让我们不断的进步。
技术是日新月异的,他不会等待你的成长。技术要拿出来于别人交流,自己学是自己主观意识上的理解,有对有错!交流会让进步变得更快。我认为如果计算机的体系结构不发生革命性的变化,我们现在所应用的程序语言也就百变不离奇踪了!学编程学的是什么?思想!精通一门编程语言(最好是面向对象的语言)后再去搞其他的编程语言,你会发现过程是如此的行云流水!为什么?你已经把编程的思想掌握了,再去学其他的,无非是学习一种新的语法格式了。
我在这里并不是和你讨论怎么去用C++或JAVA,也不是和你讨论怎么去学他们,我要和你讨论的是怎么去理解面向对象。其中主要会涉及到“类、对象、继承、属性、方法、静态、重载、隐藏、重构、声明、定义、初始化、赋值等”其中有许多相关技术我只会一代而过,让你有一种到此一游的意味我就达到目的了,而更详细的技术内幕,就请参考其他相关书籍而深入研究吧!因为我只是在和你探讨如何去更好的理解面向对象!
如何去提高效率?重复使用资源,把别人的东西拿来就用。这是很不错的主意!而对于你来说,最大的资源就是信心以及积极性!好,打起精神来,让我们一同到面向对象的编程中去寻幽访胜吧!
注:文章中所有程序实例我都使用JAVA写的,当然在C++中也就大同小异了了,不同的地方我会指出!
注:文章中的正文文字用黑色,说明文字用蓝色,强调文字用橙色,批改文字用红色!
正文:
1.基本概念:
1.1 类与对象的初探
要我说,无论是面向过程的语言也好,面向对象的语言也罢,我首先要给他讲的都是类和对象!--------“这个世界是由什么组成的?”这个问题如果让不同的人来回答会得到不同的答案。如果是一个化学家,他也许会告诉你“还用问嘛?这个世界是由分子、原子、离子等等的化学物质组成的”。如果是一个画家呢?他也许会告诉你,“这个世界是由不同的颜色所组成的”。……呵呵,众说纷纭吧!但如果让一个分类学家来考虑问题就有趣的多了,他会告诉你“这个世界是由不同类型的物与事所构成的”好!作为面向对象的程序员来说,我们要站在分类学家的角度去考虑问题!是的,这个世界是由动物、植物等组成的。动物又分为单细胞动物、多细胞动物、哺乳动物等等,哺乳动物又分为人、大象、老虎……就这样的分下去了!
现在,站在抽象的角度,我们给“类”下个定义吧!我的意思是,站在抽象的角度,你回答我“什么是人类?”首先让我们来看看人类所具有的一些特征,这个特征包括属性(一些参数,数值)以及方法(一些行为,他能干什么!)。每个人都有身高、体重、年龄、血型等等一些属性。人会劳动、人都会直立行走、人都会用自己的头脑去创造工具等等这些方法!人之所以能区别于其它类型的动物,是因为每个人都具有人这个群体的属性与方法。“人类”只是一个抽象的概念,它仅仅是一个概念,它是不存在的实体!但是所有具备“人类”这个群体的属性与方法的对象都叫人!这个对象“人”是实际存在的实体!每个人都是人这个群体的一个对象。老虎为什么不是人?因为它不具备人这个群体的属性与方法,老虎不会直立行走,不会使用工具等等!所以说老虎不是人!
由此可见-------类描述了一组有相同特性(属性)和相同行为(方法)的对象。在程序中,类实际上就是数据类型!例如:整数,小数等等。整数也有一组特性和行为。面向过程的语言与面相对象的语言的区别就在于,面向过程的语言不允许程序员自己定义数据类型,而只能使用程序中内置的数据类型!而为了模拟真实世界,为了更好的解决问题,往往我们需要创建解决问题所必需的数据类型!面向对象编程为我们提供了解决方案。
1.2 内置数据类型与函数:
计算机程序在存储数据时必须跟踪3个基本属性为:
1. 信息存储在何处;
2. 存储的值是多少;
3. 存储的信息是什么类型的;
让我们来看看编程语言的内置数据类型都有哪些!(呵呵,这个不大好说,因为每门语言都有自己独特的数据类型,但这毕竟是少数,比如在JAVA中有byte类型的数据,而在C++中就没有,希望你能举一反三!)比如整数”int ”,浮点类型的数据”float”!字符串”String”,以及数组还有结构体等等。然而在写程序的时候,根据需要我们会创建一个类型的变量或常量,例如:由于我们需要创建一个整形的变量i为5,我们就可以这样做,int i = 5;而根据需要我很有可能改变i的值,也就是从新给它赋值,比如让它等与6,就可以在所需的地方改成i = 6;由此我们知道,在“值”上可以发生变化的量就叫变量。不会发生变化的量就叫做常量了,在C++中用count关键字来声明,而在JAVA中则使用final关键字来声明。由于不同语言的声明格式不一样,这里就不做一一介绍了,详细的内容清查阅相关书籍!阅读全文
PHP截取中文字符串方法总结:
PHP截取中文字符串方法总结
程序一:PHP截取中文字符串方法
由于网站首页以及vTigerCRM里经常在截取中文字符串时出现乱码(使用substr),今天找到一个比较好的截取中文字符串方法,在此与大家共享。
function msubstr($str, $start, $len) {
$tmpstr = "";
$strlen = $start + $len;
for($i = 0; $i < $strlen; $i++) {
if(ord(substr($str, $i, 1)) > 0xa0) {
$tmpstr .= substr($str, $i, 2);
$i++;
} else
$tmpstr .= substr($str, $i, 1);
}
return $tmpstr;
}
程序二:PHP截取UTF-8字符串,解决半字符问题
/******************************************************************
* PHP截取UTF-8字符串,解决半字符问题。
* 英文、数字(半角)为1字节(8位),中文(全角)为3字节
* @return 取出的字符串, 当$len小于等于0时, 会返回整个字符串
* @param $str 源字符串
* $len 左边的子串的长度
****************************************************************/
function utf_substr($str,$len)
{
for($i=0;$i<$len;$i++)
{
$temp_str=substr($str,0,1);
if(ord($temp_str) > 127)
{
$i++;
if($i<$len)
{
$new_str[]=substr($str,0,3);
$str=substr($str,3);
}
}
else
{
$new_str[]=substr($str,0,1);
$str=substr($str,1);
}
}
return join($new_str);
}
?>
php utf-8 字符串截取
function cutstr($string, $length) {
preg_match_all("/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xef][\x80-\xbf][\x80-\xbf]|\xf0[\x90-\xbf][\x80-\xbf][\x80-\xbf]|[\xf1-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf]/", $string, $info);
for($i=0; $i $wordscut .= $info[0][$i];
$j = ord($info[0][$i]) > 127 ? $j + 2 : $j + 1;
if ($j > $length - 3) {
return $wordscut." ...";
}
}
return join('', $info[0]);
}
$string="242432反对感是456犯得上广泛大使馆地方7890";
for($i=0;$i {
echo cutstr($string,$i)."
";
}
?>
截取utf-8字符串函数
为了支持多语言,数据库里的字符串可能保存为UTF-8编码,在网站开发中可能需要用php截取字符串的一部分。为了避免出现乱码现象,编写如下的UTF-8字符串截取函数
关于utf-8
UTF-8编码的字符可能由1~3个字节组成, 具体数目可以由第一个字节判断出来。(理论上可能更长,但这里假设不超过3个字节)
第一个字节大于224的,它与它之后的2个字节一起组成一个UTF-8字符
第一个字节大于192小于224的,它与它之后的1个字节组成一个UTF-8字符
否则第一个字节本身就是一个英文字符(包括数字和一小部分标点符号)。
以前为某网站设计的代码(也是现在用在首页的长度截取的函数)
Code:
//$sourcestr 是要处理的字符串
//$cutlength 为截取的长度(即字数)
function cut_str($sourcestr,$cutlength)
{
$returnstr='';
$i=0;
$n=0;
$str_length=strlen($sourcestr);//字符串的字节数
while (($n<$cutlength) and ($i<=$str_length))
{
$temp_str=substr($sourcestr,$i,1);
$ascnum=Ord($temp_str);//得到字符串中第$i位字符的ascii码
if ($ascnum>=224) //如果ASCII位高与224,
{
$returnstr=$returnstr.substr($sourcestr,$i,3); //根据UTF-8编码规范,将3个连续的字符计为单个字符
$i=$i+3; //实际Byte计为3
$n++; //字串长度计1
}
elseif ($ascnum>=192) //如果ASCII位高与192,
{
$returnstr=$returnstr.substr($sourcestr,$i,2); //根据UTF-8编码规范,将2个连续的字符计为单个字符
$i=$i+2; //实际Byte计为2
$n++; //字串长度计1
}
elseif ($ascnum>=65 && $ascnum<=90) //如果是大写字母,
{
$returnstr=$returnstr.substr($sourcestr,$i,1);
$i=$i+1; //实际的Byte数仍计1个
$n++; //但考虑整体美观,大写字母计成一个高位字符
}
else //其他情况下,包括小写字母和半角标点符号,
{
$returnstr=$returnstr.substr($sourcestr,$i,1);
$i=$i+1; //实际的Byte数计1个
$n=$n+0.5; //小写字母和半角标点等与半个高位字符宽...
}
}
if ($str_length>$cutlength){
$returnstr = $returnstr . "...";//超过长度时在尾处加上省略号
}
return $returnstr;
}
PHP截取中文字符串方法总结
程序一:PHP截取中文字符串方法
由于网站首页以及vTigerCRM里经常在截取中文字符串时出现乱码(使用substr),今天找到一个比较好的截取中文字符串方法,在此与大家共享。
function msubstr($str, $start, $len) {
$tmpstr = "";
$strlen = $start + $len;
for($i = 0; $i < $strlen; $i++) {
if(ord(substr($str, $i, 1)) > 0xa0) {
$tmpstr .= substr($str, $i, 2);
$i++;
} else
$tmpstr .= substr($str, $i, 1);
}
return $tmpstr;
}
程序二:PHP截取UTF-8字符串,解决半字符问题
/******************************************************************
* PHP截取UTF-8字符串,解决半字符问题。
* 英文、数字(半角)为1字节(8位),中文(全角)为3字节
* @return 取出的字符串, 当$len小于等于0时, 会返回整个字符串
* @param $str 源字符串
* $len 左边的子串的长度
****************************************************************/
function utf_substr($str,$len)
{
for($i=0;$i<$len;$i++)
{
$temp_str=substr($str,0,1);
if(ord($temp_str) > 127)
{
$i++;
if($i<$len)
{
$new_str[]=substr($str,0,3);
$str=substr($str,3);
}
}
else
{
$new_str[]=substr($str,0,1);
$str=substr($str,1);
}
}
return join($new_str);
}
?>
php utf-8 字符串截取
function cutstr($string, $length) {
preg_match_all("/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xef][\x80-\xbf][\x80-\xbf]|\xf0[\x90-\xbf][\x80-\xbf][\x80-\xbf]|[\xf1-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf]/", $string, $info);
for($i=0; $i
$j = ord($info[0][$i]) > 127 ? $j + 2 : $j + 1;
if ($j > $length - 3) {
return $wordscut." ...";
}
}
return join('', $info[0]);
}
$string="242432反对感是456犯得上广泛大使馆地方7890";
for($i=0;$i
echo cutstr($string,$i)."
";
}
?>
截取utf-8字符串函数
为了支持多语言,数据库里的字符串可能保存为UTF-8编码,在网站开发中可能需要用php截取字符串的一部分。为了避免出现乱码现象,编写如下的UTF-8字符串截取函数
关于utf-8
UTF-8编码的字符可能由1~3个字节组成, 具体数目可以由第一个字节判断出来。(理论上可能更长,但这里假设不超过3个字节)
第一个字节大于224的,它与它之后的2个字节一起组成一个UTF-8字符
第一个字节大于192小于224的,它与它之后的1个字节组成一个UTF-8字符
否则第一个字节本身就是一个英文字符(包括数字和一小部分标点符号)。
以前为某网站设计的代码(也是现在用在首页的长度截取的函数)
Code:
//$sourcestr 是要处理的字符串
//$cutlength 为截取的长度(即字数)
function cut_str($sourcestr,$cutlength)
{
$returnstr='';
$i=0;
$n=0;
$str_length=strlen($sourcestr);//字符串的字节数
while (($n<$cutlength) and ($i<=$str_length))
{
$temp_str=substr($sourcestr,$i,1);
$ascnum=Ord($temp_str);//得到字符串中第$i位字符的ascii码
if ($ascnum>=224) //如果ASCII位高与224,
{
$returnstr=$returnstr.substr($sourcestr,$i,3); //根据UTF-8编码规范,将3个连续的字符计为单个字符
$i=$i+3; //实际Byte计为3
$n++; //字串长度计1
}
elseif ($ascnum>=192) //如果ASCII位高与192,
{
$returnstr=$returnstr.substr($sourcestr,$i,2); //根据UTF-8编码规范,将2个连续的字符计为单个字符
$i=$i+2; //实际Byte计为2
$n++; //字串长度计1
}
elseif ($ascnum>=65 && $ascnum<=90) //如果是大写字母,
{
$returnstr=$returnstr.substr($sourcestr,$i,1);
$i=$i+1; //实际的Byte数仍计1个
$n++; //但考虑整体美观,大写字母计成一个高位字符
}
else //其他情况下,包括小写字母和半角标点符号,
{
$returnstr=$returnstr.substr($sourcestr,$i,1);
$i=$i+1; //实际的Byte数计1个
$n=$n+0.5; //小写字母和半角标点等与半个高位字符宽...
}
}
if ($str_length>$cutlength){
$returnstr = $returnstr . "...";//超过长度时在尾处加上省略号
}
return $returnstr;
}
进入http://localhost/phpmyadmin,在创建数据库前
1、把mysql连接校对的选项改为gb2312_chinese_ci
2、而且把整理这个选项也改为gb2312_chinese_ci
然后在php连接MYSQL的语句加上 mysql_query("set names 'gbk'");
如:
include("settings.inc.php");
$conn=mysql_connect($hostname,$username,$password);
if(!$conn) die("mysql error:".mysql_error());
mysql_query("set names 'gbk'"); //这就是指定数据库字符集,一般放在连接数据库后面就系了
mysql_select_db($database,$conn);
大家喝的是啤酒。这时你入座了。
你给自己倒了杯可乐,这叫低配置。
你给自已倒了杯啤酒,这叫标准配置。
你给自己倒了杯茶水,这茶的颜色还跟啤酒一样,这叫木马。
你给自己倒了杯可乐,还滴了几滴醋。不仅颜色跟啤酒一样,而且不冒热气还有泡泡,这叫超级木马。
你的同事给你倒了杯白酒,这叫推荐配置!
人到齐了,酒席开始了。
你先一个人喝了一小口,这叫单元测试。
你跟旁边的人说哥们咱们随意,这叫交叉测试。
但是他说不行,这杯要干了,这叫压力测试。
于是你说那就大家一起来吧,这叫内部测试。
这个时候boss向全场举杯了,这叫公开测试。
菜过三巡,你就不跟他们客气了。
你向对面的人敬酒,这叫p2p。
你向一桌人挨个敬酒,这叫令牌环。
你说只要是兄弟就干了这杯,这叫广播。
可是你的上司jj听了不高兴了,只有兄弟么,罚酒三杯。这叫炸弹。
可是你的下级mm听了不高兴了,我喝一口,你喝一杯,这叫恶意攻击。
有一个人过来向这桌敬酒,你说不行你先过了我这关,这叫防火墙。
你的小弟们过来敬你酒,这叫一对多。
你是boss,所有人过来敬你酒,这叫服务器。
酒是一样的,可是喝法是不同的。
你喝了一杯,你大哥喝了半杯,这叫c++。
你喝了半杯,你小弟喝了一杯,这叫汇编 。
你喝了一杯,你的搭档也喝了一杯,这叫c语言。
酒是一样的,可是喝酒的人是不同的。
你越喝脸越红,这叫频繁分配释放资源。
你越喝脸越白,这叫资源不释放。
你已经醉了,却说我还能喝,叫做资源额度不足。
你明明能喝,却说我已经醉了,叫做资源保留。
酒过三巡,你也该活动活动了。
你一桌一桌地走,这叫轮巡。
你突然看到某一桌的漂亮mm,走了过去,这叫优先级。
你去了坐下来就不打算走了,这叫死循环。
你的老大举杯邀你过去,你只好过去,这叫激活事件。
你向一桌敬酒,他们说不行不行我们都喝白的,于是你也喝白的,这叫本地化。
你向boss敬酒,可是boss被围了起来,你只能站在外圈,这叫排队。
你终于到了内圈,小心翼翼地向前一步,这叫访问临界区。
你拍着boss的肩膀说哥们咱们喝一杯,这叫越界。
可是还有人拿着酒瓶跑过来说,刚才都没跟你喝,这叫丢包。
喝酒喝到最后的结果都一样!
你突然跑向厕所,这叫捕获异常。
你在厕所吐了,反而觉得状态不错,这叫清空内存。
你在台面上吐了,觉得很惭愧,这叫程序异常。
你在boss面前吐了,觉得很害怕,这叫系统崩溃。
你吐到了boss身上,只能索性晕倒了,这叫硬件休克。
你找boss喝酒,boss说我喝不下了,这叫超过最大连接数。
你继续劝boss喝酒,这叫刷新。
boss说喝不了了,不喝了,这叫访问拒绝。
然后boss说:小伙子,我们换个话题,这叫页面重定向。
boss问你:小伙子,你叫什么?这叫登录验证。
boss说:你等等,我去下wc。结果左等右等就是等不回来,这叫连接超时。
你到处找boss,结果就是找不到,这叫该页无法显示。
你给自己倒了杯可乐,这叫低配置。
你给自已倒了杯啤酒,这叫标准配置。
你给自己倒了杯茶水,这茶的颜色还跟啤酒一样,这叫木马。
你给自己倒了杯可乐,还滴了几滴醋。不仅颜色跟啤酒一样,而且不冒热气还有泡泡,这叫超级木马。
你的同事给你倒了杯白酒,这叫推荐配置!
人到齐了,酒席开始了。
你先一个人喝了一小口,这叫单元测试。
你跟旁边的人说哥们咱们随意,这叫交叉测试。
但是他说不行,这杯要干了,这叫压力测试。
于是你说那就大家一起来吧,这叫内部测试。
这个时候boss向全场举杯了,这叫公开测试。
菜过三巡,你就不跟他们客气了。
你向对面的人敬酒,这叫p2p。
你向一桌人挨个敬酒,这叫令牌环。
你说只要是兄弟就干了这杯,这叫广播。
可是你的上司jj听了不高兴了,只有兄弟么,罚酒三杯。这叫炸弹。
可是你的下级mm听了不高兴了,我喝一口,你喝一杯,这叫恶意攻击。
有一个人过来向这桌敬酒,你说不行你先过了我这关,这叫防火墙。
你的小弟们过来敬你酒,这叫一对多。
你是boss,所有人过来敬你酒,这叫服务器。
酒是一样的,可是喝法是不同的。
你喝了一杯,你大哥喝了半杯,这叫c++。
你喝了半杯,你小弟喝了一杯,这叫汇编 。
你喝了一杯,你的搭档也喝了一杯,这叫c语言。
酒是一样的,可是喝酒的人是不同的。
你越喝脸越红,这叫频繁分配释放资源。
你越喝脸越白,这叫资源不释放。
你已经醉了,却说我还能喝,叫做资源额度不足。
你明明能喝,却说我已经醉了,叫做资源保留。
酒过三巡,你也该活动活动了。
你一桌一桌地走,这叫轮巡。
你突然看到某一桌的漂亮mm,走了过去,这叫优先级。
你去了坐下来就不打算走了,这叫死循环。
你的老大举杯邀你过去,你只好过去,这叫激活事件。
你向一桌敬酒,他们说不行不行我们都喝白的,于是你也喝白的,这叫本地化。
你向boss敬酒,可是boss被围了起来,你只能站在外圈,这叫排队。
你终于到了内圈,小心翼翼地向前一步,这叫访问临界区。
你拍着boss的肩膀说哥们咱们喝一杯,这叫越界。
可是还有人拿着酒瓶跑过来说,刚才都没跟你喝,这叫丢包。
喝酒喝到最后的结果都一样!
你突然跑向厕所,这叫捕获异常。
你在厕所吐了,反而觉得状态不错,这叫清空内存。
你在台面上吐了,觉得很惭愧,这叫程序异常。
你在boss面前吐了,觉得很害怕,这叫系统崩溃。
你吐到了boss身上,只能索性晕倒了,这叫硬件休克。
你找boss喝酒,boss说我喝不下了,这叫超过最大连接数。
你继续劝boss喝酒,这叫刷新。
boss说喝不了了,不喝了,这叫访问拒绝。
然后boss说:小伙子,我们换个话题,这叫页面重定向。
boss问你:小伙子,你叫什么?这叫登录验证。
boss说:你等等,我去下wc。结果左等右等就是等不回来,这叫连接超时。
你到处找boss,结果就是找不到,这叫该页无法显示。
大家学习PHP大部分都靠自学,我也不例外,不乏和我一样过去是做ASP的,刚看到PHP代码,我就感到奇怪,怎么里面这么多$啊?好奇怪啊,潜意识我觉得这东西肯定比ASP难多了,可是当我领略了PHP的神奇后(同样功能的ASP,PHP程序在我过去的C2古董机上一跑,肉眼都看看出速度的差别),我顿时被PHP的魅力吸引了(虽然现在在我的HP本本上是感觉不出差别了),同时吸引我的还有LAMP组合。于是,我的PHP学习历程开始了。。。。。。
呵呵,不知道大家学习PHP做的第一个功能是什么,我做PHP的第一个程序是接收一组表单数据,然后回显它们,成功后想到,如果是URL参数PHP怎么接受呢?查了手册,翻了书本,哦!用$_GET,也许许多从ASP过来的程序员一开始也会受ASP思路的影响,其实没有关系,一段时间就适应了,你也许会说,早知道不学ASP了,不会受影响,你错了,做久了你就会发现,过去积累的ASP经验在很大程度上帮助你更快的掌握了PHP,所谓一理通,百理明,程序都有相似,ASP可以说和PHP是很接近的,所以ASP程序员转PHP是很快的,有多快呢?下面再讲^_^,读到这里过去没学过ASP的,或者0基础的朋友可别不看了,什么?我这分明是写给过去做过ASP的人看的嘛,其实都一样,我强调的是学习的方法和思路,不管学什么语言,这都是最重要的。
嗯,你学会了基本语法,了解了内部函数,书本上的例子都能看懂了,肯定想试试自己的身手了吧?对,这是我强调的第一点,学习程序,就要不断写代码,这样是最快的学习方法,也是最有效的,可是忽然离开书本了,自己动手编,可能有种不知从哪开始的感觉,怎么办???我的方法是--站在巨人的肩膀上。优秀的代码永远是最好的学习工具,你建议先下个留言本看,WHY?留言本简单,且具备了一个完整系统所必须的全部条件。数据库,前后台。咱们就先从数据库部分开始,看他如何设计,分析它为什么这样设计,我能不能有更好的设计,明白了以后,看他如何和PHP交互,这里我建议大家最好学习些软件工程的知识,学会做系统分析,能划分系统模块,这样有助于大家独立设计系统。当你明白了原理之后,你就可以开始做程序,按照你想好的思路做,其中肯定会遇到种种困难,你要翻手册,找GOOGLE,问网友,甚至还有调试程序时的烦躁,但是请千万不要放弃,成功和失败只在一念之间,往前一步,或许你就成功了,退后一步,则肯定失败。当你克服了期间困难之后,你会发现通过做这个程序,你又学会了好多东西,经验得到积累,没错,你进步了。接着干什么,留言本是不够的,把它扩展成CMS试试,做成BBS试试,如果你的系统越做越大,那么恭喜你,你一定有希望成为优秀的PHPer!
这里当然还是要介绍下调试程序的技巧,记住,如果一段程序调试不过,先判断单词拼写,在判断语法,有没漏{};之类的,可以分段echo结果,缩小调试范围,特别是数据库交互的程序,先输出个SQL语句看看,对了,再分析怎么会插入/删除不成功呢,之类的。调试程序可能会占用编程很多的时间,我们当然还是要总结自己的调试经验。当然我自己有个习惯,上网的时候看到网站有些功能不错,我就想这是怎么实现的?我能做到码?于是我就自己动手试试,无论成功与否,我觉得都会有些帮助,有助于提高水平,我这人不喜欢老重复书中那些无聊的example,在自己的动手实践中学习,我觉得效率更高,且我享受那种代码成功实现的喜悦,这也是我学习的动力。当然作为程序员,必须时刻关注程序的发展,当你入门后,你就得考虑些高级应用,你如提高下程序效率,用下模板,AJAX什么得,要时刻关注业界得动态。
最后,谈下之前说的我从ASP转PHP花多长时间,也就是我学习PHP花多长时间,老实告诉大家,半年多,其中包括学习AJAX,smarty,XAJAX得时间。也许大家有疑问,怎么可能啊???忽悠人吧,不错,我是学PHP半年多,可是请大家注意,之前学习HTML,数据库,软件工程,ASP,我花了1年多,所以大家看看,其实学习编程是没有捷径的,我们能做的就是一步一个脚印,打好基础,提高水平,充实自己,最后祝各位新手学习愉快,都能成为优秀的PHPer,壮大中国的IT力量!^_^
呵呵,不知道大家学习PHP做的第一个功能是什么,我做PHP的第一个程序是接收一组表单数据,然后回显它们,成功后想到,如果是URL参数PHP怎么接受呢?查了手册,翻了书本,哦!用$_GET,也许许多从ASP过来的程序员一开始也会受ASP思路的影响,其实没有关系,一段时间就适应了,你也许会说,早知道不学ASP了,不会受影响,你错了,做久了你就会发现,过去积累的ASP经验在很大程度上帮助你更快的掌握了PHP,所谓一理通,百理明,程序都有相似,ASP可以说和PHP是很接近的,所以ASP程序员转PHP是很快的,有多快呢?下面再讲^_^,读到这里过去没学过ASP的,或者0基础的朋友可别不看了,什么?我这分明是写给过去做过ASP的人看的嘛,其实都一样,我强调的是学习的方法和思路,不管学什么语言,这都是最重要的。
嗯,你学会了基本语法,了解了内部函数,书本上的例子都能看懂了,肯定想试试自己的身手了吧?对,这是我强调的第一点,学习程序,就要不断写代码,这样是最快的学习方法,也是最有效的,可是忽然离开书本了,自己动手编,可能有种不知从哪开始的感觉,怎么办???我的方法是--站在巨人的肩膀上。优秀的代码永远是最好的学习工具,你建议先下个留言本看,WHY?留言本简单,且具备了一个完整系统所必须的全部条件。数据库,前后台。咱们就先从数据库部分开始,看他如何设计,分析它为什么这样设计,我能不能有更好的设计,明白了以后,看他如何和PHP交互,这里我建议大家最好学习些软件工程的知识,学会做系统分析,能划分系统模块,这样有助于大家独立设计系统。当你明白了原理之后,你就可以开始做程序,按照你想好的思路做,其中肯定会遇到种种困难,你要翻手册,找GOOGLE,问网友,甚至还有调试程序时的烦躁,但是请千万不要放弃,成功和失败只在一念之间,往前一步,或许你就成功了,退后一步,则肯定失败。当你克服了期间困难之后,你会发现通过做这个程序,你又学会了好多东西,经验得到积累,没错,你进步了。接着干什么,留言本是不够的,把它扩展成CMS试试,做成BBS试试,如果你的系统越做越大,那么恭喜你,你一定有希望成为优秀的PHPer!
这里当然还是要介绍下调试程序的技巧,记住,如果一段程序调试不过,先判断单词拼写,在判断语法,有没漏{};之类的,可以分段echo结果,缩小调试范围,特别是数据库交互的程序,先输出个SQL语句看看,对了,再分析怎么会插入/删除不成功呢,之类的。调试程序可能会占用编程很多的时间,我们当然还是要总结自己的调试经验。当然我自己有个习惯,上网的时候看到网站有些功能不错,我就想这是怎么实现的?我能做到码?于是我就自己动手试试,无论成功与否,我觉得都会有些帮助,有助于提高水平,我这人不喜欢老重复书中那些无聊的example,在自己的动手实践中学习,我觉得效率更高,且我享受那种代码成功实现的喜悦,这也是我学习的动力。当然作为程序员,必须时刻关注程序的发展,当你入门后,你就得考虑些高级应用,你如提高下程序效率,用下模板,AJAX什么得,要时刻关注业界得动态。
最后,谈下之前说的我从ASP转PHP花多长时间,也就是我学习PHP花多长时间,老实告诉大家,半年多,其中包括学习AJAX,smarty,XAJAX得时间。也许大家有疑问,怎么可能啊???忽悠人吧,不错,我是学PHP半年多,可是请大家注意,之前学习HTML,数据库,软件工程,ASP,我花了1年多,所以大家看看,其实学习编程是没有捷径的,我们能做的就是一步一个脚印,打好基础,提高水平,充实自己,最后祝各位新手学习愉快,都能成为优秀的PHPer,壮大中国的IT力量!^_^
我在夏天前一定把肚子减下来,。增加运动。合理进食!
i can’t believe I’m standing here Been waiting for so many years and Today