花了不少时间和心思作了这个东西, 使用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);
 }
}
?>

在许多应用软件运行时都带有命令行参数,其实这些命令行参数在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);
 今天上班发现phpmyadmin出现:出现空白页面或无法载入 mysql 扩展。
查了一下原来是php.ini配置有问题:
修改如下:
1. extension_dir = 和PHP实际的ext目录不一致。(默认当前目录)
2. 没有把PHP目录和ext目录添加到环境变量中。(修改path)
3. extension=php_mysql.dll等前的;注释没去掉。(去掉;)
4. Zend安装目录和php.ini中Zend指定的目录不一致。

把上面几种情况检查一下,若还不能解决,请使用其他方法
1、父子二人经过五星级饭店门口,看到一辆十分豪华的进口轿车。儿子不屑地对他的父亲说:「坐这种车的人,肚子里一定没有学问!」父亲则轻描淡写地回答:「说这种话的人,口袋里一定没有钱!」 (注:你对事情的看法,是不是也反映出你内心真正的态度?) 
  2、晚饭后,母亲和女儿一块儿洗碗盘,父亲和儿子在客厅看电视。突然,厨房里传来打破盘子的响声,然后一片沉寂。是儿子望着他父亲,说道:「一定是妈妈打破的。」「你怎么知道?」「她没有骂人。」
  (注:我们习惯以不同的标准来看人看己,以致往往是责人以严,待己以宽。) 
     
  3、有两个台湾观光团到***伊豆半岛旅游,路况很坏,到处都是坑洞。其中一位导游连声抱歉,说路面简直像麻子一样。说而另一个导游却诗意盎然地对游客说:诸位先生女士,我们现在走的这条道路,正是赫赫有名的伊豆迷人酒窝大道。」 
  (注:虽是同样的情况,然而不同的意念,就会产生不同的态度。思想是何等奇妙的事,如何去想,决定权在你。) 
     
  4、同样是小学三年级的学生,在作文中说他们将来的志愿是当小丑。中国的老师斥之为:「胸无大志,孺子不可教也!」带外国的老师则会说:「愿你把欢笑带给全世界!」 
  (注:身为长辈的我们,不但容易要求多于鼓励,更狭窄的界定了成功的定义。) 
  5、在故宫博物院中,有一个太太不耐烦地对她先生说:「我说你为甚么走得这么慢。原来你老是停下来看这些东西。」 
  (注:有人只知道在人生的道路上狂奔,结果失去了观看两旁美丽花朵的机会。) 
6、妻子正在厨房炒菜。丈夫在她旁边一直唠叨不停:慢些。小心!火太大了。赶快把鱼翻过来。快铲起来,油放太多了!把豆腐整平一下!「哎?」妻子***口而出,「我懂得怎样炒菜。」「你当然懂,太太,」丈夫平静地答道:「我只是要让你知道,我在开车时,你在旁边喋喋不休,我的感觉如何。」 
  注:学会体谅他人并不困难,只要你愿意认真地站在对方的角度和立场看问题。) 
     
  7、理由充份 
  一辆载满乘客的公共汽车沿着下坡路快速前进着,有一个人後面紧紧地追赶着这辆车子。一个乘客从车窗中伸出头来对追车子的人说:“老兄!算啦,你追不上的!”“我必须追上它,”这人气喘吁吁地说:“我是这辆车的司机!” 
  (注:有些人必须非常认真努力,因为不这样的话,後果就十分悲惨了!然而也正因为必须全力以赴,潜在的本能和不为人知的特质终将充份展现出来。) 
     
  8、原来如此 
  甲:「新搬来的邻居好可恶,昨天晚上三更半夜、夜深人静之时然跑来猛按我家的门铃。」乙:「的确可恶!你有没有马上报警?」甲:「没有。我当他们是疯子,继续吹我的小喇叭。」 
  (事出必有因,如果能先看到自己的不是,答案就会不一样在你面对冲突和争执时,先想一想是否心中有亏,或许很快就能释怀了。) 
     
  9、误会 
  某日,张三在山间小路开车,正当他悠哉地欣赏美丽风景时,突然迎面开来一辆货车,而且满囗黑牙的司机还摇下窗户对他大骂一声:“猪!” 
  张三越想越纳闷,也越想越气,於是他也摇下车窗回头大骂:“你才是猪!” 
  才刚骂完,他便迎头撞上一群过马路的猪。 
  (不要错误的诠释别人的好意,那只会让自己吃亏,并且使别人受辱。在不明所以之前,先学会按捺情绪,耐心观察,以免事後生发悔意。)
10、後生可畏 
  小男孩问爸爸:“是不是做父亲的总比做儿子的知道得多?” 
  爸爸回答:“当然啦!” 
  小男孩问:“电灯是谁发明的?” 
  爸爸:“是爱迪生。” 
  小男孩又问:“那爱迪生的爸爸怎麽没有发明电灯?” 
  (很奇怪,喜欢倚老卖老的人,特别容易栽跟斗。权威往往只是一个经不起考验的空壳子,尤其在现今这个多元开放的时代。) 
     
  11、不必紧张 
  小明洗澡时不小心吞下一小块肥皂,他的妈妈慌慌张张地打电话向家庭医生求助。医生说:“我现在还有几个病人在,可能要半小时後才能赶过去。” 
  小明妈妈说:“在你来之前,我该做甚麽?” 
  医生说:“给小明喝一杯白开水,然後用力跳一跳,你就可以让小明用嘴巴吹泡泡消磨时间了。” 
  (take it easy,放轻松放轻松些,生活何必太紧张?事情既然已经发生了,何不坦然自在的面对。担心不如宽心,穷紧张不如穷开心。) 
     
  12、钥匙 
  一把坚实的大锁挂在大门上,一根铁杆费了九牛二虎之力,还是无法将它撬开。钥匙来了,他瘦小的身子钻进锁孔,只轻轻一转,大锁就“啪”地一声打开了。 
  铁杆奇怪地问:“为什麽我费了那麽大力气也打不开,而你却轻而易举地就把它打开了呢?” 
  钥匙说:“因为我最了解他的心。” 
  (每个人的心,都像上了锁的大门,任你再粗的铁棒也撬不开)
这个网址破解很快的,对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已经成功建立!";

?>
一篇经典的文章----面向对象思想----不看后悔!


前言:
  整理这份资料的目的是为了帮助朋友们能够更直观的理解面向对象的编程。让后来者能够少走一些弯路。但其中不免有许多漏洞及错误,也还请前辈提出宝贵的更改意见,毕竟交流会让我们不断的进步。
  技术是日新月异的,他不会等待你的成长。技术要拿出来于别人交流,自己学是自己主观意识上的理解,有对有错!交流会让进步变得更快。我认为如果计算机的体系结构不发生革命性的变化,我们现在所应用的程序语言也就百变不离奇踪了!学编程学的是什么?思想!精通一门编程语言(最好是面向对象的语言)后再去搞其他的编程语言,你会发现过程是如此的行云流水!为什么?你已经把编程的思想掌握了,再去学其他的,无非是学习一种新的语法格式了。
  我在这里并不是和你讨论怎么去用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;

}

进入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);

大家学习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力量!^_^
mysql 5.0的就必须指定校验字符
(解放牌)  2007-04-07 16:25:47
config t(10202001) 10:43:16
mysql 5.0的就必须指定校验字符

怎么指定?
(ō雲下遮雨)  2007-04-07 16:26:27
mysql_query("SET NAMES UTF8")
(☆風)  2007-04-07 16:38:06
不一定是 utf8 啊
大家可能觉的很奇怪!公安部门的是怎样去抓到黑客的呢?其实除了和电信部门取得合作以外很大程度上他们都把抓黑客的事情交给所谓的"技术部门"这些技术部门不像你相象的那么厉害![当然也不能笼统的说] 其中一个最老套也命中率最高的办法就是通过日志记录的IP来排查。

  可能有人会问:我已经删除了日志文件还会被抓?告诉你:89。5%会的![这个百分比可不是我编出来的哦]。不废话了!

  技术部门的办法:例如我2004年7月19日晚8:39分31秒用小榕的日志擦写软件擦掉了全部IP或者指定IP.技术部门拿到这家倒霉公司的硬盘先做备份,然后用类似FinalData. EasyRecovery 或者别的什么磁盘恢复软件按时间表来恢复前一小时或者前一分钟的所有文件,然后就.......!你是不是叫***你被捕了,你有权保持沉默但是你所讲的将回成为....

  所以大家如果入侵的是比较棘手的地方或者什么部门的话!两个字:小心!

解决办法:用类似改写扇区删除软件来删除日志文件!因为WINDOWS里的都是模拟删除!即使你用format c:如果你不加参数还是可以恢复的!

网络上找了一下!发现了这个!

3. SecWiper V1.0

[简要说明]

SecWiper是一个运行在Windows上的安全地擦除文件的控制台小工具,一旦擦除,永远丢失,风险自负责!

功能简列如下:

1、支持Windows 9x/me/nt/2000/...

2、严格按照国际安全擦除标准执行动作

3、可彻底删除文件,并且支持通配符

4、可彻底删除目录,可包含所有子目录

5、可彻底清除空闲磁盘里所有可能被恢复的文件

6、确保清除后的文件用FinalData、RecoverNT、EasyRecovery等数据恢复工具无法恢复


  你们会问你怎么知道这些的,难道.........[放心我还没有被抓进去过@@~!]
至少现在还没有.


  还是一句话!没有事情不要乱搞别人的主机!我一般也就利用一下他们的宽带空间什么的从来没有覆盖过**公司的主页或者format c:等行为!因为我做事考虑的是后果,好处坏处占的比例。
“武汉男生”,俗称“熊猫烧香”,这是一个感染型的蠕虫病毒,它能感染系统中exe,com,pif,src,html,asp等文件,它还能中止大量的反病毒软件进程并且会删除扩展名为gho的文件,该文件是一系统备份工具GHOST的备份文件,使用户的系统备份文件丢失。

瑞星熊猫烧香专杀工具
http://download.rising.com.cn/zsgj/NimayaKiller.scr

江民熊猫烧香专杀工具
http://www.jiangmin.com/download/zhuansha04.htm

金山熊猫烧香专杀工具
http://tool.duba.net/zhuansha/253.shtml阅读全文
时下视频网站实在是太火了,而其用到的技术也一直是处于半公开状态,我在大概3个月前,开始接触这个技术,当时的资料并不多,在经过一个多星期的研究之后,终于大功告成!

起初,看到一些视频网站,觉得挺新奇的,能够把上传的视频文件转成FLV格式,而且还会有几张截图出来,当时在想,是不是网站专门请了一批人处理这些上传的文件,然后把图截出来,现在想想这念头确实挺幼稚的。

其实说白了,也挺简单的,就是通过php的执行函数,比如exec,然后调用服务器的转换程序,转换结束后将文件生成到指定的文件夹,更新数据库记录,并转到相应的页面。

因为要上传比较大的文件,所以要先设置最大上传文件的大小,打开php.ini,找到upload_max_filesize,这一行,将值改为50M或更大。

至于转换程序的选择,我最初是用ffmpeg的,但是发现转换经常失败,不得不放弃,后来发现另一款非常棒的转换软件,mencoder,也是linux下的,但我的环境是windows,所以找到了一个绿色的以mencoder为核心的应用软件wisMencoder,里面有mencoder,如果是从网上下的话,应该有三个相应的mencoder,分别是对应不同的处理器的。

如果要生成截图,可以通过ffmpeg来生成。

下面是核心代码:
程序代码

exec ("$cgi_url $source_url -o $dest_url -of lavf -oac mp3lame -lameopts abr:br=56 -ovc lavc -lavcopts vcodec=flv:vbitrate=500:mbd=2:mv0:trell:v4mv:cbp:last_pred=3:dia=4:cmp=6:vb_strategy=1 -vf scale=320:240,expand=320:240:::1,crop=320:240:0:0 -ofps 30 -srate 22050 -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames",$arr,$sta);
if($sta!=0){
   die ("转换出错!");
}
//优化生成的flv
exec("flvmdi.exe $dest_url");
$imgW="160";
$imgY="120";
exec("ffmpeg.exe -i $dest_url -ss 10 -vframes 1 -r 1 -ac 1 -ab 2 -s $imgW*$imgY -f image2 $pic_url");
echo "文件转换完毕";
if(filesize($pic_url)=="0"){
   echo "文件转换出错";
}

这里解释一下,上面的$cgi_url,指的是要调用的转换程序的url,$source_url指的是上传的文件的url,$dest_url,是生成的flv的存放路径,后面的参数比较复杂,就不具体解释了,网上应该有相应的文章,最后的$sta,是判断是否转换成功
调用flvmdi.exe是因为mencoder生成的flv不能拖放,用这个程序来修复一下
最后调用ffmpeg来生成截图
当然转换生成结束后还要更新一下数据库记录

顺便提一句,由于上传的文件可能比较大,所以最好将php的执行时间相应延长,比如延长到300秒
set_time_limit(300);

至此视频网站的最核心技术就完全捅破了,如果还有什么问题,欢迎和我交流。
Mplayer是Linux下功能超强的电影播放器,当然它也可以播放mp3,wma等声音格式文件.
以下流程在RedHat9下通过,适合对Linux有初步了解的朋友:

1、下载安装所需文件:
(1)主程序: http://www1.mplayerhq.hu/MPlayer/releases/MPlayer-1.0pre5.tar.bz2
(2)字体文件: http://www1.mplayerhq.hu/MPlayer/releases/fonts/font-arial-iso-8859-1.tar.bz2
(3)Skin文件(支持GUI): http://www1.mplayerhq.hu/MPlayer/Skin/plastic-1.2.tar.bz2

当然也可以下载其他皮肤文件
(4)支持avi等w32多媒体格式插件:

http://www1.mplayerhq.hu/MPlayer/releases/codecs/win32codecs-20040703.tar.bz2

(5) 支持realplay(rm,ram等)等多媒体格式插件

http://www1.mplayerhq.hu/MPlayer/releases/codecs/essential-20040704.tar.bz2



如果只是在控制台(文本)下运行,只用下载(1)(4)(5),如果想要图形界面并支持中文,以上5个都要下载。


2、把以上5个文件拷入/root下(可以自己选择目录),解压:
[root@localhost root]# tar jxvf MPlayer-1.0pre5.tar.bz2
[root@localhost root]# tar jxvf font-arial-iso-8859-1.tar.bz2
[root@localhost root]# tar jxvf plastic-1.2.tar.bz2

[root@localhost root]# tar jxvf win32codecs-20040703.tar.bz2
[root@localhost root]# tar jxvf essential-20040704.tar.bz2



解压后的文件名比较长,可以考虑通过mv或ln等命令进行文件夹改名或连接,方便下面过程的进行。本文档没有做文件名处理。


3、拷贝w32codec支持库(win32codecs-20040703)及realplay支持库(essential-20040704)

一定要先执行这一步,而且拷入的目录一定要注意,如果你已安装了realplay8或realplay9也可不需拷入realplay的支持库,只是下面运行configure时要注意它所在的目录。
[root@localhost root]# mkdir /usr/lib/win32
[root@localhost root]# cp /root/win32codecs-20040703/* /usr/lib/win32
[root@localhost root]# cp -r /root/essential-20040704 /usr/lib


4、进入Mplayer安装目录并执行,注意参数:
[root@localhost root]# cd MPlayer-1.0pre5
[root@localhost MPlayer-1.0pre5]# ./configure --enable-gui --disable-gcc-checking --with-reallibdir=/usr/lib/essential-20040704 --language=zh_CN
(不建议加上 --disable-gcc-checking 参数----jiangtao9999)

#说明:--enable-gui是用来支持图形界面的播入器,--disable-gcc-checking是用来跳过对gcc版本的检查(但不保证在所有的linux下都能通过下面的操作。如有这种情况,请说明),--with-reallibdir=/usr/lib/essential- 20040704是用来指定realplay支持库所在的目录。如果你已安装了realplay 8那这个选项应该为:--with-reallibdir=/usr/lib/RealPlay8/codecs 如果你已安装了realplay 9(你可根据实际修改):--with-reallibdir=/root/Real/codecs, –-language=zh_CN是用来指定Mplayer的字体为中文。1.0版本已经支持rtsp流,所以不用 –-enable-live。


5、依次执行:
[root@localhost MPlayer-1.0pre5]# make
[root@localhost MPlayer-1.0pre5]# make install


6、拷入字体:
[root@localhost MPlayer-1.0pre5]# cp /root/ font-arial-iso-8859-1/font-arial-14-iso-8859-1/* /usr/local/share/mplayer/font/


7、拷入Skin:
[root@localhost MPlayer-1.0pre5]# cp -r /root/plastic /usr/local/share/mplayer/Skin/default



注意Skin的首字母要大写


8、拷入input.conf文件:
[root@localhost MPlayer-1.0pre5]# cp /root/ MPlayer-1.0pre5/etc/input.conf /usr/local/share/mplayer/


9、在X下运行gmplayer 可启动图形界面播入模式,控制台下运行mplayer可以启动字符播放模式。



关于Mplayer播放器的使用很简单,自己摸索一下就知道了。

反正你按照我的的方面一步一步做下去一定能装成功.
class Page{//分页类
var $table;//表名
var $n;//每页显示条数
var $d;//当前页
var $num;//总条数
var $j;//一共几页
var $start;//起始位置
var $url;//当前文件
var $py;//偏移几个单位,以当前页为中心对称偏移
var $yc;//溢出多少个单位,以3,5,7.....
 
function Getallnum($sql){//得到总条数
 global $conn;
 $this->table=$table;
 $all=$conn->GetAll($sql);
 $this->num=count($all);
 return $this->num;
}
function Getallpage($n){//得到一共几页
 $this->n=$n;
 $this->j=ceil($this->num/$this->n);
 return $this->j;
}
function Getpage($d,$url){//分页
 $d=$_GET['page'];
 $this->d=$d;
 $this->url=$url;
 if (empty($this->d) || $this->d <0 || $this->d==0 || $this->d==1){
  $this->d=1;
  if(($this->j)>1){
   $str="首页";
   $str.=$this->mathurl(2,5);
   $str.="下一页";
  }
 }elseif(($this->d)>=$this->j){
  $this->d=$this->j;
  $str="上一页";
  $str.=$this->mathurl(2,5);
  $str.="尾页";
 }else{
  $str="上一页";
  $str.=$this->mathurl(2,5);
  $str.="下一页";
 }
 return $str;
 return $this->d;
 return $this->url;
}
function Getstart(){//起始位置
 if(empty($this->d)){
  $this->start=0;
 }else{
  $this->start=$this->n*($this->d-1);
 }
 return $this->start;
}
function Getend($e){//每页显示条数
 return $this->d=$e;
}
function options(){//跳转菜单
 $opt=" ";
 return $opt;
}
function mathurl($py,$yc){//数字导航
 $this->py=$py;
 $this->yc=$yc;
 $co=$_GET['page'];//当前页码
 $do=$this->j;//总页数
 if($this->j<=$this->yc){//总页数小于或等于$yc时
  for ($o=1;$o<=$this->j;$o++){
   $murl.=" ".$o." ";
  }  
 }elseif($co>($do-$this->py)){//页码超过总页数时
  $co=$do;
  for ($v=($co-($this->yc-1));$v<=$do;$v++){//往左偏移$yc个单位
   $murl.=" ".$v." ";
  }
 }elseif($co<=$this->py){
  $co=1;
  for ($v=$co;$v<($co+$this->yc);$v++){//往右偏移$yc个单位
   $murl.=" ".$v." ";
  }
 }else{
  for($k=($co-$this->py);$k<$co;$k++){//往左偏移$py个单位
  $murl.=" ".$k." ";
  }  
  for ($v=$co;$v<=($co+$this->py);$v++){//往右偏移$py个单位
   $murl.=" ".$v." ";
  }
 }
 return $murl;  
}
}/*
require_once("../class/Smarty.class.php");
include "../adodb/adodb.inc.php";
include "../connect.php";
$page=new Page();
$sql="select * from class";
$p['num']=$page->Getallnum($sql);
$p['page']=$page->Getallpage(10);
$p['link']=$page->Getpage(1,"class.inc.php?");
$p['start']=$page->Getstart(0);
$p['end']=$page->Getend(10);
$p['opt']=$page->options();
$a=$conn->GetAll("select * from class limit ".$p['start'].",".$p['end']."");
--------------------------上面的是数据库分页的例子-------------------------------
--------------------------下面的是搜索分页的例子--------------------------------------
$s=$_GET['s'];
$si=$_POST['s'];
if(empty($_GET['key'])){
$key=$si;
}else{
$key=$_GET['key'];
}
if($s=="s"){
$page=new Page();
$sqa="select cname from class where cname like binary  '%".$key."%'";
$p['num']=$page->Getallnum($sqa);
$p['page']=$page->Getallpage(6);
$p['link']=$page->Getpage(1,"class.inc.php?s=s&key=".$key."&");
$p['start']=$page->Getstart(0);
$p['end']=$page->Getend(6);
$sql="select cname from class where cname like binary  '%".$key."%' limit ".$p['start'].",".$p['end']."";  
$rs=$conn->GetAll($sql);
}
-------------------------下面的是smarty应用-------------------------------------------------
$smarty = new Smarty;
$smarty->assign("page",$p);
$smarty->assign("show",$a);
//$smarty->assign("se",$rs);
$smarty->display('class.inc.htm');
*/
?>
分页: 262/272 第一页 上页 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 下页 最后页 [ 显示模式: 摘要 | 列表 ]