<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[suibing的博客]]></title> 
<link>http://www.suibing.com/index.php</link> 
<description><![CDATA[suibing的新博客，欢迎大家捧场~~]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[suibing的博客]]></copyright>
<item>
<link>http://www.suibing.com/post/259/</link>
<title><![CDATA[yum 安装nginx0.8.X php-fpm]]></title> 
<author>suibing &lt;admin@yourname.com&gt;</author>
<category><![CDATA[技术文章]]></category>
<pubDate>Mon, 21 Jun 2010 13:31:23 +0000</pubDate> 
<guid>http://www.suibing.com/post/259/</guid> 
<description>
<![CDATA[ 
	 Create repo<br/># cd /etc/yum.repos.d<br/># vim rusia-repo.repo<br/><br/>- and paste this<br/><div class="code"><br/>&#91;rusia-repo&#93;<br/>name=CentOS-$releasever – rusia packages for $basearch<br/>baseurl=http://centos.alt.ru/repository/centos/5/$basearch/<br/>enabled=1<br/>gpgcheck=0<br/>protect=1 <br/><br/></div><br/><br/><div class="code"><br/>rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/$(uname -m)/epel-release-5-3.noarch.rpm<br/></div><br/><br/><div class="code"><br/>yum install nginx php-fpm<br/></div><br/><br/><br/><br/>
]]>
</description>
</item><item>
<link>http://www.suibing.com/post/258/</link>
<title><![CDATA[Linux VPS下简单解决CC攻击]]></title> 
<author>suibing &lt;admin@yourname.com&gt;</author>
<category><![CDATA[技术文章]]></category>
<pubDate>Tue, 08 Jun 2010 13:34:59 +0000</pubDate> 
<guid>http://www.suibing.com/post/258/</guid> 
<description>
<![CDATA[ 
	一，准备工作<br/>1，登录进VPS控制面板，准备好随时重启VPS。<br/>2，关闭Web Server先，过高的负载会导致后面的操作很难进行，甚至直接无法登录SSH。<br/>3，以防万一，把设置的Web Server系统启动后自动运行去掉。<br/>（如果已经无法登录进系统，并且重启后负载过高导致刚刚开机就已经无法登录，可联系管理员在母机上封掉VPS的IP或80端口，在母机上用虚拟控制台登录进系统，然后进行2&3的操作，之后解封）<br/><br/>二，找出攻击者IP<br/><br/>1，在网站根目录建立文件ip.php，写入下面的内容。复制内容到剪贴板代码:<br/><div class="code"><br/>&lt;?php<br/>$real_ip = getenv(&#039;HTTP_X_FORWARDED_FOR&#039;);<br/>if(isset($real_ip))&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shell_exec(&quot;echo $real_ip &gt;&gt; real_ip.txt&quot;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shell_exec(&quot;echo $_SERVER&#91;&#039;REMOTE_ADDR&#039;&#93; &gt;&gt; proxy.txt&quot;);<br/>&#125;else&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shell_exec(&quot;echo $_SERVER&#91;&#039;REMOTE_ADDR&#039;&#93; &gt;&gt; ips.txt&quot;);&nbsp;&nbsp;<br/>&#125;<br/><br/>echo &#039;服务器受到攻击，正在收集攻击源，请在5分钟后访问本站，5分钟内多次访问本站有可能会被当作攻击源封掉IP。谢谢合作！&#039;;<br/>?&gt;<br/></div><br/><br/>2，设置伪静态，将网站下的所有访问都rewrite到ip.php。<br/>Nginx规则：<br/><div class="code"><br/>rewrite (.*) /ip.php;<br/></div><br/><div class="code"><br/>Lighttpd规则：复制内容到剪贴板代码:<br/>url.rewrite = (<br/>&quot;^/(.+)/?$&quot; =&gt; &quot;/ip.php&quot;<br/>)<br/></div><br/>3，启动Web Server开始收集IP<br/>进行完1和2的设置后，启动Web Server，开始记录IP信息。<br/>收集时间建议为3到5分钟，然后再次关闭Web Server。<br/>real_ip.txt，这个文件中保存的IP有80%以上都相同的，这个IP就是攻击者实施攻击的平台的IP。<br/>proxy.txt，这个文件中保存的是攻击者调用的代理服务器的IP，需要封掉。<br/>ips.txt，这里记录的是未表现出代理服务器特征的IP，根据访问次数判断是否为攻击源。<br/><br/>三，对上一段的补充<br/>如果VPS上启用了WEB日志，可以查看日志文件的增长速度来判断是哪个站点被攻击。<br/>如果没有启用日志，并且站点数量很少，临时启用日志也很方便 。<br/>如果没有启用日志，并且站点数量过多，可以使用临时的Web Server配置文件，不绑定虚拟主机，设置一个默认的站点。然后在ip.php里加入下面一行<br/><div class="code"><br/>shell_exec(“echo $_SERVER&#91;&#039;HTTP_HOST&#039;&#93; &gt;&gt; domain.txt”);<br/></div><br/>domain.txt里将保存被访问过的域名，被CC攻击的站点将在里面占绝大多数。<br/><br/><br/>四，开始封堵IP<br/>建立文件ban.php<br/><div class="code"><br/>&lt;?<br/>$threshold = 10;<br/>$ips = array_count_values(file(&#039;ips.txt&#039;));<br/>$ban_num = 0;<br/>foreach($ips as $ip=&gt;$num)&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;if($num &gt; $threshold)&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$ip = trim($ip);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$cmd = &quot;iptables -I INPUT -p tcp --dport 80 -s $ip -j DROP&quot;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shell_exec($cmd);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;$ip baned!&#92;n&quot;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$ban_num ++;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&#125;<br/><br/>$proxy_arr = array_unique(file(&#039;proxy.txt&#039;));<br/>foreach($proxy_arr as $proxy)&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;proxy = trim($proxy);<br/>&nbsp;&nbsp;&nbsp;&nbsp;$cmd = &quot;iptables -I INPUT -p tcp --dport 80 -s $proxy -j DROP&quot;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;shell_exec($cmd);<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;$proxy baned!&#92;n&quot;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;$ban_num ++;<br/>&#125;<br/><br/>echo &quot;total: $ban_num ips&#92;n&quot;;<br/>?&gt;<br/></div><br/>用下面的命令执行脚本（确保php命令在PATH中）复制内容到剪贴板代码:<br/>php ban.php这个脚本依赖于第二段中ips.txt里保存的结果，当其中记录的IP访问次数超过10次，就被当作攻击源给屏蔽掉。如果是代理服务器，则不判断次数直接封掉。<br/>封完IP之后，把所有的网站设置恢复正常，站点可以继续正常运行了。<br/><br/><br/>五，一些细节<br/>为保持对操作过程的描述尽量简洁，没有在上面的内容中加入过多的解释，留在这段统一讲述。<br/>1，关于“代理服务器”的一些本质<br/>两个与TCP&HTTP协议相关的值，REMOTE_ADDR和HTTP_X_FORWARDED_FOR。<br/>（1）REMOTE_ADDR总是取离Web服务器最接近的一台主机的IP，如果没有使用代理，这个值就是访问者本身的IP，如果使用了代理，这个值就是代理服务器的IP，如果通过多个代理服务器进行的连接，这个值就是到达Web服务器前最后一台代理服务器的IP。<br/>REMOTE_ADDR是由TCP/IP层决定的，不能修改不能伪造。<br/>（2）HTTP_X_FORWARDED_FOR，因为这个值是属于HTTP部分，而不是TCP/IP，所以这个值不管是什么，都不影响数据的传输。事实上，一般情况下，如果是访问者直接访问Web服务器，这个值为空；通过透明代理的时候，这个值会被代理服务器设置为访问者的IP；通过匿名代理连接时，这个值可能为代理服务器的IP也可能是空的也有可能是随机的。<br/>HTTP_X_FORWARDED_FOR可以被任意修改。大多数代理服务器都是透明代理，也就是说，会把这个值设置为最原始访问者的IP。<br/><br/>2，关于解决CC攻击的层面问题<br/>按处理效率从高到低排列。<br/>（由于本文是针对VPS服务器所写，而VPS简单来说就是服务器的低端替代品，内存和CPU等资源普遍偏低，当然是处理效率越高越好。）<br/>（1）网络传输层。也就是本文所用的iptables，这个工具本身是工作于系统内核，在建立网络连接时直接把攻击者的连接给否了。在这一层面上将攻击源处理掉后，消耗掉的资源几乎可以忽略不计。<br/>（2）Web Server层，大多数Web Server都可以设置禁止访问的IP。在这一层上解决的意义和上面的差不多，但是效率要差些。<br/>（3）脚本层，从脚本程序上制定适合于本身的策略过滤掉攻击源。网络上有很多流传的在这一层面的解决方案，但是不太适用于VPS，而且设置难度可能要增加几倍或者几十倍。<br/><br/>3，为什么不是从日志收集IP？<br/>主要是考虑两点，一是大多数VPS使用者都因为硬盘空间过小，经常清除日志很麻烦，而直接禁止了日志。<br/>二是如果从日志收集IP，脚本复杂程度要高很多，而且可能要根据情况做些调整，考虑到将要读到本文的人大多数都未必掌握更多的技术，本文的目的就是按部就班的依本文进行操作，即可解决问题。<br/><br/><br/>六，其他<br/>本文版权归www.diahosting.com所有，转载请保留超链接。<br/><br/>
]]>
</description>
</item><item>
<link>http://www.suibing.com/post/256/</link>
<title><![CDATA[人民日报：中方向美国承诺，将完善国民收入分配格局]]></title> 
<author>suibing &lt;admin@yourname.com&gt;</author>
<category><![CDATA[网络趣闻]]></category>
<pubDate>Thu, 03 Jun 2010 12:42:39 +0000</pubDate> 
<guid>http://www.suibing.com/post/256/</guid> 
<description>
<![CDATA[ 
	这次中美经济对话<br/><br/>中方向美国承诺，将完善国民收入分配格局，逐渐增加居民收入占国民收入的比重。加强社会保障体系建设，改革垄断行业。<br/><br/><br/>&nbsp;&nbsp;http://cq.people.com.cn/news/2010526/201052693245.htm<br/><br/><br/>　　本国人民的福祗却要向美国承诺,我终于明白了谁在代表中国最广大人民群众的根本利益。<br/><br/><br/><br/>------------------------这才是真正的超级囧的冷笑话！！！
]]>
</description>
</item><item>
<link>http://www.suibing.com/post/255/</link>
<title><![CDATA[CListCtrl控件的使用 ]]></title> 
<author>suibing &lt;admin@yourname.com&gt;</author>
<category><![CDATA[技术文章]]></category>
<pubDate>Sun, 30 May 2010 07:52:59 +0000</pubDate> 
<guid>http://www.suibing.com/post/255/</guid> 
<description>
<![CDATA[ 
	初始化:<br/> DWORD dwStyle;<br/> dwStyle = m_bzlist.GetStyle();<br/> dwStyle &#124;= LVS_EX_GRIDLINES &#124;LVS_EX_FULLROWSELECT&#124;LVS_SHOWSELALWAYS ;<br/> m_bzlist.SetExtendedStyle(dwStyle);<br/> m_bzlist.SetBkColor(RGB(0xec,0xf1,0xfd));<br/> m_bzlist.SetTextBkColor(RGB(0xfe,0xFF,0xc6));<br/>插入一列:<br/> m_bzlist.InsertColumn(0,"编号");<br/> m_bzlist.SetColumnWidth(0,50);<br/>插入一行:<br/>方法1:<br/> LV_ITEM lvitem;<br/> lvitem.pszText="";<br/> lvitem.mask=LVIF_TEXT;<br/> lvitem.iSubItem=0;<br/> lvitem.iItem=0;<br/> m_jbxxlist.InsertItem(&lvitem);<br/> m_jbxxlist.SetItemText(0,0,xh);<br/> m_jbxxlist.SetItemText(0,1,xm);<br/> m_jbxxlist.SetItemText(0,2,nj);<br/> 方法2:<br/> m_yktlist.InsertItem(i,"2");<br/> m_yktlist.SetItemText(i,0,s);&nbsp;&nbsp;<br/> m_yktlist.SetItemText(i,1,xh);<br/> m_yktlist.SetItemText(i,2,xm);<br/>读取数据<br/>&nbsp;&nbsp;resultlist.GetItemText(行数, 列数); <br/>&nbsp;&nbsp;<br/>每行前有复选框的列表:<br/>初始化时使用LVS_EX_CHECKBOXES属性<br/>DWORD dwStyle;<br/>dwStyle = m_yktlist.GetStyle();<br/>dwStyle &#124;= LVS_EX_GRIDLINES &#124;LVS_EX_FULLROWSELECT&#124;LVS_EX_CHECKBOXES ;<br/>m_yktlist.SetExtendedStyle(dwStyle);<br/>设置选中:<br/>m_yktlist.SetItemState (行数,0x2000, LVIS_STATEIMAGEMASK);//设为选中状态<br/>判断是否选中:<br/>m_yktlist.GetItemState(行数,LVIS_STATEIMAGEMASK)==0x2000//选中<br/> <br/> <br/>&nbsp;&nbsp; <br/>实现点击列头排序: <br/>定义可以排序的列表类<br/>只需要多定义两个变量<br/>class SortCListCtrl : public CListCtrl<br/>&#123;<br/>// Construction<br/>public:<br/> SortCListCtrl();<br/><br/>// Attributes<br/>public:<br/> BOOL m_fAsc;//是否顺序排序<br/> int m_nSortedCol;//当前排序的列<br/> ....<br/>&#125;<br/>在使用可以排序列表时 实例化自己的变量 <br/>SortCListCtrl m_yktlist;<br/><br/><br/>//响应点击列函数<br/>void CAuditingCertView::OnColumnclickListYkt(NMHDR* pNMHDR, LRESULT* pResult) <br/>&#123;<br/> <br/> for (int i = 0; i < m_yktlist.GetItemCount(); ++i)<br/> &#123;<br/>&nbsp;&nbsp;m_yktlist.SetItemData(i, i);//供排序使用的item编号<br/> &#125;<br/> <br/> NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;<br/> <br/> //设置排序方式<br/> if( pNMListView->iSubItem ==m_yktlist.m_nSortedCol )<br/>&nbsp;&nbsp;m_yktlist.m_fAsc = !m_yktlist.m_fAsc;<br/> else<br/> &#123;<br/>&nbsp;&nbsp;m_yktlist.m_fAsc = TRUE;<br/>&nbsp;&nbsp;m_yktlist.m_nSortedCol = pNMListView->iSubItem;<br/> &#125;<br/> //调用排序函数,此函数为CListCtrl定义好的,但是需要调用我们定义的函数才比较任意两个项目的值<br/> m_yktlist.SortItems(MyListCompare, (LPARAM)&m_yktlist); <br/><br/> for ( i = 0; i < m_yktlist.GetItemCount(); ++i)&#123;<br/>&nbsp;&nbsp;m_yktlist.SetItemData(i, i);//供排序使用的item编号<br/>&nbsp;&nbsp;CString s;<br/>&nbsp;&nbsp;s.Format("%d",i+1);//编号<br/>&nbsp;&nbsp;m_yktlist.SetItemText(i,0,s);<br/>&nbsp;&nbsp;<br/> &#125;<br/> *pResult = 0;<br/>&#125;<br/><br/>///全局函数,比较两个项目的依据<br/>int CALLBACK&nbsp;&nbsp;MyListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)<br/>&#123;<br/> //通过传递的参数来得到CSortList对象指针，从而得到排序方式<br/> SortCListCtrl * pV=(SortCListCtrl *)lParamSort;<br/> //通过ItemData来确定数据<br/> CString szComp1,szComp2;<br/> int iCompRes;<br/> szComp1=pV->GetItemText(lParam1,pV->m_nSortedCol);<br/> szComp2=pV->GetItemText(lParam2,pV->m_nSortedCol);<br/> switch(pV->m_nSortedCol)<br/> &#123;<br/> case(0):<br/>&nbsp;&nbsp;//以第一列为根据排序 编号<br/>&nbsp;&nbsp;iCompRes=atof(szComp1)<=atof(szComp2)?-1:1;<br/>&nbsp;&nbsp;break;<br/> case(4):<br/>&nbsp;&nbsp;//以第5列为根据排序 总次数<br/>&nbsp;&nbsp;iCompRes=atof(szComp1)<=atof(szComp2)?-1:1;<br/>&nbsp;&nbsp;break;<br/> default:<br/>&nbsp;&nbsp;iCompRes=szComp1.Compare(szComp2);<br/>&nbsp;&nbsp;break;<br/> &#125;<br/> //根据当前的排序方式进行调整<br/> if(pV->m_fAsc)<br/>&nbsp;&nbsp;return iCompRes;<br/> else<br/>&nbsp;&nbsp;return -iCompRes;<br/> <br/> <br/>&#125;<br/><br/>导出数据为excel文件<br/>使用ODBC将数据输出到excel数据区&nbsp;&nbsp;<br/>void ExportAsExcel(CString filename,CListCtrl &resultlist,CWnd * wnd)<br/>&#123;<br/> CDatabase database;<br/> CString sDriver = "MICROSOFT EXCEL DRIVER (*.XLS)"; // Excel安装驱动<br/> CString sSql,sExcelFile;<br/> //弹出对话框选择路径<br/>&nbsp;&nbsp;&nbsp;&nbsp;CFileDialog fileDlg (FALSE, "Path", filename,OFN_FILEMUSTEXIST&#124; OFN_HIDEREADONLY, "*.xls",wnd);<br/> if( fileDlg.DoModal()==IDOK)<br/> &#123;<br/>&nbsp;&nbsp;sExcelFile = fileDlg.GetPathName();&nbsp;&nbsp;&nbsp;&nbsp;// 要建立的Excel文件<br/>&nbsp;&nbsp;CFileFind finder;<br/>&nbsp;&nbsp;BOOL bWorking = finder.FindFile(sExcelFile);//寻找文件<br/>&nbsp;&nbsp;if (bWorking)//如果已经存在文件,则删除<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp; CFile::Remove((LPCTSTR)sExcelFile);<br/>&nbsp;&nbsp;&#125;<br/> <br/> &#125;<br/> else return;<br/> <br/> TRY<br/> &#123;<br/>&nbsp;&nbsp;// 创建进行存取的字符串<br/>&nbsp;&nbsp;sSql.Format("DRIVER=&#123;%s&#125;;DSN='';FIRSTROWHASNAMES=1;READONLY=FALSE;CREATE_DB=&#92;"%s&#92;";DBQ=%s",sDriver, sExcelFile, sExcelFile);<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;// 创建数据库 (既Excel表格文件)<br/>&nbsp;&nbsp;if( database.OpenEx(sSql,CDatabase::noOdbcDialog) )<br/>&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp; CHeaderCtrl* pHeader = resultlist.GetHeaderCtrl();<br/>&nbsp;&nbsp; //获得行，列的个数<br/>&nbsp;&nbsp; int nColCount = pHeader->GetItemCount();<br/>&nbsp;&nbsp; int nLineCount = resultlist.GetItemCount();<br/>&nbsp;&nbsp; int ColOrderArray[100];<br/>&nbsp;&nbsp; CString ca[100];<br/>&nbsp;&nbsp; resultlist.GetColumnOrderArray(ColOrderArray, nColCount);<br/>&nbsp;&nbsp; //检索各列的信息，确定列标题的内容<br/>&nbsp;&nbsp; for(int i =0 ; i< nColCount; i++)<br/>&nbsp;&nbsp; &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;LVCOLUMN lvc;<br/>&nbsp;&nbsp;&nbsp;&nbsp;char text[100];<br/>&nbsp;&nbsp;&nbsp;&nbsp;lvc.mask = LVCF_TEXT&#124;LVCF_SUBITEM;<br/>&nbsp;&nbsp;&nbsp;&nbsp;lvc.pszText = text;<br/>&nbsp;&nbsp;&nbsp;&nbsp;lvc.cchTextMax = 100;<br/>&nbsp;&nbsp;&nbsp;&nbsp;resultlist.GetColumn(ColOrderArray[i], &lvc);<br/>&nbsp;&nbsp;&nbsp;&nbsp;ca[i] = lvc.pszText;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp; &#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp; <br/>&nbsp;&nbsp; // 创建表结构<br/>&nbsp;&nbsp; CString tempsql="(";<br/>&nbsp;&nbsp; for(i =0 ; i< nColCount-1; i++)<br/>&nbsp;&nbsp; &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;tempsql+=ca[i];<br/>&nbsp;&nbsp;&nbsp;&nbsp;tempsql+=" TEXT,";<br/>&nbsp;&nbsp;&nbsp;&nbsp; <br/>&nbsp;&nbsp; &#125;<br/>&nbsp;&nbsp; tempsql+=ca[nColCount-1];<br/>&nbsp;&nbsp; tempsql+=" TEXT)";<br/>&nbsp;&nbsp; sSql = "CREATE TABLE Sheet1 ";<br/>&nbsp;&nbsp; sSql+=tempsql;<br/>&nbsp;&nbsp; database.ExecuteSQL(sSql);<br/>&nbsp;&nbsp; //插入数据<br/>&nbsp;&nbsp; int item_count=resultlist.GetItemCount();<br/>&nbsp;&nbsp; tempsql="(";<br/>&nbsp;&nbsp; for(i =0 ; i< nColCount-1; i++)<br/>&nbsp;&nbsp; &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;tempsql+=ca[i];<br/>&nbsp;&nbsp;&nbsp;&nbsp;tempsql+=" ,";<br/>&nbsp;&nbsp;&nbsp;&nbsp; <br/>&nbsp;&nbsp; &#125;<br/>&nbsp;&nbsp; tempsql+=ca[nColCount-1];<br/>&nbsp;&nbsp; tempsql+=")";<br/>&nbsp;&nbsp; for(int itemnum=0;itemnum<item_count;itemnum++)&#123;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;sSql="";<br/>&nbsp;&nbsp;&nbsp;&nbsp;sSql ="INSERT INTO Sheet1 ";<br/>&nbsp;&nbsp;&nbsp;&nbsp;sSql+=tempsql;<br/>&nbsp;&nbsp;&nbsp;&nbsp;sSql+="VALUES ('";<br/>&nbsp;&nbsp;&nbsp;&nbsp;for(i =0 ; i< nColCount-1; i++)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp; sSql+=resultlist.GetItemText(itemnum, i);<br/>&nbsp;&nbsp;&nbsp;&nbsp; sSql+="','";<br/>&nbsp;&nbsp;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;sSql+=resultlist.GetItemText(itemnum, nColCount-1);<br/>&nbsp;&nbsp;&nbsp;&nbsp;sSql+="')";<br/>&nbsp;&nbsp;&nbsp;&nbsp;database.ExecuteSQL(sSql);<br/>&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp; &#125;<br/>&nbsp;&nbsp; <br/>&nbsp;&nbsp; <br/>&nbsp;&nbsp;&#125;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;// 关闭数据库<br/>&nbsp;&nbsp;database.Close();<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;AfxMessageBox("Excel文件写入成功！");<br/> &#125;<br/> CATCH_ALL(e)<br/> &#123;<br/>&nbsp;&nbsp;TRACE1("Excel驱动没有安装: %s",sDriver);<br/> &#125;<br/> END_CATCH_ALL; <br/>&#125; <br/><br/>CListCtrl控件在数据库编程中是用得比较多的控件之一，也是Window控件中较难掌握的一个控件。他可以有四显示方式，在这里只介绍报表方式，因为在数据库开发程序中使用很经常。 <br/><br/>　　在Report方式中，列表控件的显示方式是有行和列的，行有叫做Item，但有多列是我们只能操作每一行的第零列，也就是最前列。 <br/><br/>插入列，使用的是InsertColumn <br/><br/>设置完列后我们就可以设置列表控件的数据了 <br/><br/>使用的是InsertItem和setItemText <br/><br/>其中InsertItem用于向列表控件插入一行，并设置第零列的值，如果有多列，该行其他列的值要使用SetItemText来设置数据。 <br/><br/>当然最关键的问题是：怎么获取CListCtrl对象的Item数据 <br/><br/>我们可以使用这样一个函数GetNextItem(-1,LVNI_ALL &#124; LVNI_SELECTED)来获取当前选中的行（Item）如果该函数还回的值是-1，说明没有行（item）被选中，如果有行被选中，还回的是一个大于等于0的整数值，我们可以通过这个索引值来得到该行的相关列的数据，使用的是GetItemText（）函数 <br/><br/>int CurSel=m_list.GetNextItem(-1,LVNI_ALL &#124; LVNI_SELECTED); <br/><br/>str=m_list.GetItemText(CurSel,col); 0=<col<m_list的列数<br/><br/>CHeaderCtrl *header=m_List.GetHeaderCtrl(); <br/>int iCols=header->GetItemCount(); <br/>CString s; <br/>HDITEM hditem; <br/>char Buffer[256]=&#123;0&#125;; <br/>TRACE("&#92;n"); <br/>for(int i=0;i<iCols;i++) <br/>&#123; <br/>hditem.mask=HDI_TEXT; <br/>hditem.cchTextMax=256; <br/>hditem.pszText=Buffer; <br/>header->GetItem(i,&hditem); <br/>s.Format("第%d列 标题:%s&#92;n",i,Buffer); <br/>TRACE(s); <br/><br/>&#125; <br/><br/><br/>
]]>
</description>
</item><item>
<link>http://www.suibing.com/post/254/</link>
<title><![CDATA[vmview4发生错误Desktop Composer Fault: Virtual Machine with input specifications already exists 的解决方案]]></title> 
<author>suibing &lt;admin@yourname.com&gt;</author>
<category><![CDATA[个人日记]]></category>
<pubDate>Thu, 20 May 2010 01:42:03 +0000</pubDate> 
<guid>http://www.suibing.com/post/254/</guid> 
<description>
<![CDATA[ 
	删除以下表的内容即可<br/><br/>#<br/><br/><br/>delete from SVI_SC_BASE_DISK_KEYS<br/>where PARENT_ID = (SELECT ID FROM SVI_SIM_CLONE<br/>WHERE (VM_NAME = ‘<VM-NAME>’))<br/><br/>delete from SVI_SC_PDISK_INFO<br/>where PARENT_ID = (SELECT ID FROM SVI_SIM_CLONE<br/>WHERE (VM_NAME = ‘<VM-NAME>’))<br/><br/>delete FROM SVI_SIM_CLONE<br/>WHERE (VM_NAME = ‘<VM-NAME>’)<br/><br/><br/><br/>You cannot provision a linked clone desktop pool&nbsp;&nbsp;<br/>You see the error:<br/><br/>Desktop Composer Fault: 'Virtual Machine with Input Specification already exists<br/>&nbsp;&nbsp;<br/>Provisioning a linked clone desktop pool fails with the error:<br/><br/>Virtual machine with Input Specification already exists<br/>&nbsp;&nbsp;<br/>The Connection Server shows that linked clone virtual machines are stuck in a Deleting state <br/>Resolution<br/>This issue occurs if a table in the database has incorrect data. You must delete the pae-VM object from the ADAM database and from the View Composer database so the tables regenerate properly. <br/>Removing the virtual machine from the ADAM database<br/>Find the virtual machine's GUID stored in ADAM:<br/>Log in to the culprit virtual machine using the VMware Infrastructure (VI) Client Console or directly using Windows RDP. <br/>Open the Windows registry, go to HKEY_LOCAL_MACHINE&#92;SOFTWARE&#92;VMware, Inc.&#92;VMware VDM&#92;Node Manager&#92;Server DN. <br/>Record the cn=<GUID>. <br/>To delete the pae-VM object from the ADAM database:<br/>Click Start > Programs > ADAM > ADAM ADSI Edit to open the ADAM Active Directory Service Interfaces Editor. <br/>Right-click ADAM ADSI Edit and click Connect to.<br/>Choose Distinguished name (DN) or naming context and type dc=vdi, dc=vmware, dc=int.<br/><br/>Note: For more information about ADSI Edit, see http://technet.microsoft.com/en-us/library/cc773354%28WS.10%29.aspx.<br/>The preceding link was correct as of July 15, 2009. If you find the link is broken, provide feedback and a VMware employee will update the link.<br/><br/><br/>Locate the OU=SERVERS container.<br/>Locate the corresponding virtual machine's GUID (from above) in the list which can be sorted in ascending or descending order, choose Properties and check the pae-DisplayName Attribute to verify the corresponding linked clone virtual machine object.<br/>Delete the pae-VM object.<br/>Removing the linked clone references from the View Composer database<br/>To remove the linked clone references from the View Composer database:<br/><br/>Open SQL Manager > Databases > View Composer database > Tables. <br/>Open dbo.SVI_VM_NAME table and delete the entire row where the virtual machine is referenced under column NAME. <br/>Open dbo.SVI_COMPUTER_NAME table and delete the entire row where the virtual machine is referenced under column NAME. <br/>Open dbo.SVI_SIM_CLONE table, find the virtual machine reference under column VM_NAME and note the ID. If you try to delete this row it complains about other table dependencies. <br/>Open dbo.SVI_SC_PDISK_INFO table and delete the entire row where dbo.SVI_SIM_CLONE ID is referenced under column PARENT_ID. <br/>Open dbo.SVI_SC_BASE_DISK_KEYS table and delete the entire row where dbo.SVI_SIM_CLONE ID is referenced under column PARENT_ID. <br/>If the linked clone was in the process of being deployed when a problem occurred, there may be additional references to the clone left around in the dbo.SVI_TASK_STATE table and dbo.SVI_REQUEST table. <br/>Open dbo.SVI_TASK_STATE table and find the row where dbo.SVI_SIM_CLONE ID is referenced under column SIM_CLONE_ID. Note the REQUEST_ID in that row. <br/>Open dbo.SVI_REQUEST table and delete the entire row where dbo.SVI_TASK_STATE REQUEST_ID is referenced ID. <br/>Delete the entire row from dbo.SVI_TASK_STATE table.<br/>&nbsp;&nbsp;<br/>In dbo.SVI_SIM_CLONE table, delete the entire row where the virtual machine is referenced. <br/>Remove the virtual machine from Active Directory Users and Computers. <br/>Deleting the virtual machine from VirtualCenter<br/>To delete the virtual machine from VirtualCenter:<br/><br/>Log in to VirtualCenter using the VI Client. <br/>Right-click the linked clone virtual machine and click Delete from Disk. <br/><br/>
]]>
</description>
</item><item>
<link>http://www.suibing.com/post/253/</link>
<title><![CDATA[OpenVZ型VPS安装Teredo接入IPv6]]></title> 
<author>suibing &lt;admin@yourname.com&gt;</author>
<category><![CDATA[个人日记]]></category>
<pubDate>Fri, 23 Apr 2010 15:35:13 +0000</pubDate> 
<guid>http://www.suibing.com/post/253/</guid> 
<description>
<![CDATA[ 
	&nbsp;&nbsp;没有原生提供IPv6的XEN型VPS可以在Hurricane Electric申请一个TunnelBroker接入IPv6，对OpenVZ型VPS，由于目前绝大多数VPS的提供的OpenVZ内核没有打上虚拟sit0设备的补丁，所以不能使用TunnelBroker(已经可用，参阅http://www.lostriver.net/linux-userspace-6to4-tun/)。但如果VPS提供TUN/TAP设备，可以通过Teredo接入IPv6。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Linux上的开源Teredo客户端叫Miredo。对于Ubuntu/Debian，Miredo已经有了deb安装包，开启TUN/TAP后运行apt-get install miredo，再次用ifconfig查看时，名为teredo的TUN/TAP接口已经配置完成，IPv6前缀为2001:0:53aa:64c:。惟一一点遗憾是Miredo占用了约30M内存(是在保存peer list么？)，对于小内存VPS有些压力。另外注意每次reboot或者重启Miredo进程后，IPv6地址将会改变。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Teredo也可以为位于IPv4 NAT内的主机提供IPv6接入(6to4必须要客户端有public IPv4 address)，完整的Teredo接入需要客户端、Teredo Server和Teredo Relay。(Wiki在此)。由于需要bubble packet，国内又没有Teredo Relay(中国CERNET2内，可见的Teredo Relay位于欧洲)，第一个IPv6数据包往返可能长达1000ms，后续数据包往返大约在300ms+。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Teredo接入与6to4类似，对于不同的IPv6地址使用不同的中继；不同之处是Teredo Relay在IPv6网络anycast 2001::/32前缀，而6to4 Relay除在IPv6网anycast 2002::/16，还在IPv4网络anycast 192.88.99.1。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CERNET2有线路tein3至欧洲，目前到本站IPv6的Teredo中继是funet.fi(芬兰)，延时200ms+，再从芬兰到美国的VPS又加上100ms延时。带宽十分充裕，但在高峰时段丢包率达到25%，v4和v6线路都有丢包。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一般来说同时具有IPv4与IPv6地址的域名，将优先使用IPv6访问。但对于Teredo接入IPv6，系统会优先使用IPv4访问以获得更好的接入质量。所以添加IPv6域名应慎重，对于CERNET用户，系统会优先使用IPv4访问，经过几十秒超时后才使用IPv6，体验极差。<br/><br/><br/><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6to4可以在没有原生IPv6接入时构建IPv6 over IPv4隧道。该协议已经被linux内核所支持，内核提供了虚拟设备sit自动配置IPv6隧道。很多ISP也提供免费的TunnelBroker。但如果内核没有支持sit设备（比如现在大多数OpenVZ的VPS的内核时都没有支持sit），则在运行<br/><br/># ip tunnel add 6to4 mode sit<br/>会出现<br/><br/>ioctl: No such device<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;搜索了一下，似乎还没有运行于linux的第三方程序能建立6to4隧道，于是只好自己写一个。程序放在了<br/><br/>Please visit http://code.google.com/p/tb-tun/。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RFC3056包含了6to4隧道大多数细节，我只看了数据包封装，十分简单，把IPv6数据包（包括header和payload）直接作为IP数据包的packet body。注意IPv4数据包的协议类型为41(C语言里面定义常数IPPROTO_IPV6)。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;程序首先创建TUN设备，并开启SOCK_RAW监听协议41（由于用了原始套接字，运行时必须要有root权限）。然后创建两个线程s2t和t2s，s2t把sock上监听到源地址正确、协议类型为41的IP包去掉包头写入TUN设备，t2s读取TUN设备上的数据并封入IP数据包作为内容发送给Relay Server。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t2s比较容易，惟一疑惑是使用sendto()函数时，远端地址结构体remoteaddr.sin_port不知道如何填写，因为封装的不是TCP或者UDP，没有端口号。填写为htons(IPPROTO_IPV6)没有出现问题。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s2t则出现了一些问题，明明向TUN设备写入了正确的数据包，却无法正确被应用程序识别，tcpdump返回wrong link-layer encapsulationbad-hlen。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;重新查看了内核TUN/TAP设备的文档，原来TUN设备模拟点对点链路，也存在链路数据包头。通常创建TUN/TAP设备时使用了flag IFF_NO_PI缺省了链路层包头，内核自动把协议字填写为IP数据包。与实际的IPv6不符导致错误。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flag IFF_NO_PI没有设置时，链路附加包头为：<br/><br/>struct tun_pi &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;unsigned short flags;<br/>&nbsp;&nbsp;&nbsp;&nbsp;unsigned short proto;<br/>&#125;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flag仅在接收数据包时有效，这里向TUN设备写入，即发送数据包，这一字可以置0，proto应该填写htons(ETH_P_IPV6)。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;向TUN写入时，需要在从sock读取的IPv6数据包前加入4个字节的上述结构体。t2s函数也要进行相应修改，除去上述的4个字节链路包头。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如何配置6to4 tunnel参阅Google Code上的HOWTO。试验了一下资源占用，内存占用约0.5M，CPU使用为wget的2倍。没有测试过兼容性，代码也显然还有很大改进空间<br/>
]]>
</description>
</item><item>
<link>http://www.suibing.com/post/252/</link>
<title><![CDATA[详解ucenter原理及第三方应用程序整合思路、方法]]></title> 
<author>suibing &lt;admin@yourname.com&gt;</author>
<category><![CDATA[技术文章]]></category>
<pubDate>Fri, 26 Mar 2010 08:53:43 +0000</pubDate> 
<guid>http://www.suibing.com/post/252/</guid> 
<description>
<![CDATA[ 
	整合了 ucenter就等于整合了整个php界的所有php程序。<br/><br/>一、功用：<br/>不对，何止整合了整个php界的所有php程序，而是整合了 ucenter就等于整合了所有的asp/asp.net/php/jsp等其它语言的所有web应用程序。（因为ucenter client的api开发包，dz会推出其它语言版）<br/><br/>而且所有整合的程序同步登录，同步退出，同步修改密码。最终用户可以通过它轻松通行在各个应用之中，无需重复登录、注册、退出<br/><br/>一个id可以出入一个站内的所有程序，如cms和bbs,也可以一个id出入www.a.com和www.b.com及www.c.com<br/><br/>a.com的用户可以和b.com的用户互发短消息pm，a.com的用户可以和b.com的用户加好友。<br/><br/>而且可以实现站内信(pm)和其它任意站的任意程序的站内信(pm)互通。<br/><br/>可以实现www.a.com与[url]www.b.com及<a href="http://www.c.com" target="_blank">www.c.com</a>[/url]共享一个用户库，www.a.com的用户可以给<a href="http://www.b.com" target="_blank">www.b.com</a>的用户pm短信.<br/><br/>用户组与discuz不对应的问题也得到解决。因为一般应用程序的用户组是单独的一个应用，和discuz再没有关系，而是和ucenter有关系，而ucenter没有用户组的概念。<br/><br/><br/>二、整合方法：<br/>如果单说整合用户的话，整合时应用程序的改动也非常小，原数据库不用动，原写cookies的代码不用动，原写数据库session的代码不用动，原来的程序不用怎么动，只需改动以下4个文件：<br/><br/>longin.php&nbsp;&nbsp; register.php&nbsp;&nbsp; logout.php&nbsp;&nbsp; 修改密码文件.php&nbsp;&nbsp; （忘记密码.php不用动，用原来的就可以）<br/><br/>4个文件中加上和ucenter api通信的语句和逻辑结构。<br/><br/>另需要针对ucenter新增加一个文件uc.php，这个文件就是应用程序接收ucenter传来的指令并执行的文件。而且他利用p3p技术实现反向登录a.com或是同时反向登录a.com/b.com/c.com的dedecms或是phpcms或是任意所有程序。<br/><br/><br/>共计改4个文件，增一个文件。<br/><br/><br/>如果要是整合站内信pm,好友，头像等功能，思路与方法和整合用户类同。<br/><br/>另外有一点，在不同的系统之间注册的用户，在第一次登录这个从来没有登录过的系统时，会让激活。借用这个激活，可以让用户完善在本应用程序中的资料，如企业注册资料。资料不完善，不可以激活。<br/><br/>如在bbs注册一个用户test,第一次来到b2b的程序中，这时，并不会自动登录，而是要求用户激活，而test在bbs注册时填的字段与b2b中要求的不同。这时让用户完善资料。第二次来就会自动登录。<br/><br/><br/>三、 uc原理：<br/><br/>以用户登录为例介绍，其它注销，改密码，消息，头像，好友均类同。<br/><br/>1.<br/>从用户xxx在某一应用程序的login.php，输入用户名，密码讲起。<br/>先用uc_user_login函数到uc server验证此用户和密码，如正确，则写入session,写入cookies，并更新应用程序会员表中的登录ip，登录时间。用户感觉不到这个过程。<br/>2.<br/>然后通过uc_user_synlogin通知uc server 用户xxx登录成功,这个过程可能使用ajax，用户感觉不到通知过程。<br/>3.<br/>uc server收到这个消息后，马上命令手下，把xxx登录的消息，像令牌环一样，发给所有愿意接收（后台中那个是否开启同步登录）这个消息的其它应用程序。其实就是带参数访问一下各应用程序的uc.php,用户感觉不到这个过程。<br/>4.<br/>各应用程序靠api下的uc.php来接收uc server发来的消息，并对uc server言听计从，让干什么就干什么。现在，收到让xxx用户在你的程序中登录的命令，马上执行。<br/>并写本应用程序的session，并且使用p3p, 写入相同域或不同域的cookies.&nbsp;&nbsp; 用户感觉不到这个过程。<br/><br/>5.最后所有和uc整合的程序，xxx均登录成功。用户从www.test.com/bbs登录后， 跳到www.test.com/news同样显示登录。因为bbs 和news系统在后台均已登录。<br/><br/>6.应用程序与uc server的会话结束。<br/><br/><br/>得益于uc设计的精巧过程，整个过程，用户完全感觉不到ucenter的存在.这是整合程序历史上的创新。完<br/>
]]>
</description>
</item><item>
<link>http://www.suibing.com/post/251/</link>
<title><![CDATA[Ucenter 会员同步登录通讯原理]]></title> 
<author>suibing &lt;admin@yourname.com&gt;</author>
<category><![CDATA[技术文章]]></category>
<pubDate>Fri, 26 Mar 2010 08:52:37 +0000</pubDate> 
<guid>http://www.suibing.com/post/251/</guid> 
<description>
<![CDATA[ 
	1，用户登录bbs，通过logging.php文件中，使用函数uc_user_login验证，如果验证成功，将调用函数uc_user_synlogin（位于uc_client下的client.php文件中），在这个函数中调用 uc_api_post('user', 'synlogin', array('uid'=>$uid));之后向UC_API.'/index.php'传递了数据；这里的UC_API就是在config.inc.php中的定义的uc_server之URL地址<br/><br/>2，uc_server的index.php接受参数数据，获得model为user，action为synlogin，就调用control目录下的user.php类中的onsynlogin方法，通过foreach循环，以javascript的方式通知uc应用列表中的应用同步登录；即通过get方式传递给应用目录中api下的uc.php一些数据；<br/><br/>3，uc.php接收通知并处理get过来的数据，并在函数synlogin（位于uc.php中）通过函数_authcode加密数据（默认以UC_KEY作为密钥），用函数_setcookie设置cookie；<br/><br/>4，各个应用在适当的文件中用对应的密钥解码上面设置的cookie，得到用户id等数据；通过这个值来判断用户是否经过其它应用登录过；<br/><br/><a href="http://www.suibing.com/attachment.php?fid=3" target="_blank"><img src="http://www.suibing.com/attachment.php?fid=3" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>以discuz举例：<br/><br/>一、用户登录检查与用户登录验证logging.php<br/><br/>在bbs的logging.php中如下代码段<br/><br/>&#125; elseif($action == 'login') &#123;<br/><br/>if($discuz_uid) &#123;<br/><br/>&nbsp;&nbsp; $ucsynlogin = '';<br/><br/>&nbsp;&nbsp; showmessage('login_succeed', $indexname);<br/><br/>&#125;<br/><br/>检查用户id变量$discuz_uid是否为空来判断，用户是否登录（包括从别的应用登录。）<br/><br/>如果用户从bbs登录，则在登录验证成功后通过如下代码：<br/><br/>$ucsynlogin = $allowsynlogin ? uc_user_synlogin($discuz_uid) : '';<br/><br/>通知其它应用----“用户已从bbs登录，请通知其它应用设置cookie”<br/><br/>（uc_server通过javascript调用方式向其它应用的api/uc.php传递数据）<br/><br/>可以在uc应用目录下新建一个名为test.php的文件，来模拟登录成功，请求uc_server通知其它应用。文件内容为：<br/><br/>---------------------文件内容开始----------------------<br/><br/><?php<br/><br/>include_once "config.inc.php";<br/><br/>include_once "./uc_client/client.php";<br/><br/>echo uc_user_synlogin(1);<br/><br/>echo "<pre>";<br/><br/>var_dump($_COOKIE);<br/><br/>echo "</pre>";<br/><br/>?><br/><br/><script type="text/javascript"><br/><br/>var obj=document.getElementsByTagName("script");<br/><br/>for(var i=0;i<obj.length-1;i++) &#123;<br/><br/>&nbsp;&nbsp; document.write("<a href=&#92;""+obj[i].src+"&#92;">"+obj[i].src+"</a><hr>");<br/><br/>&#125;<br/><br/></script><br/><br/>---------------------文件内容结束----------------------<br/><br/>ps:这段测试代码还可以测试同步登录不好使的情况，具体使用方法，你可以思考一下(本文后面也有介绍），有问题可以在此文结尾发表评论与我讨论。<br/><br/>运行后，查看源代码即可看到javascript；<br/><br/>这里要注意了：这些javascript的通知中是不包含用户登录的应用的。也就是说只"通知"用户未登录的应用，因为用户通过uc_server登录成功的当前应用，当然不需要uc_server再通知了。具体代码请参看：webroot&#92;uc_server&#92;control&#92;user.php中的onsynlogin函数的这句：<br/><br/>if($app['synlogin'] && $app['appid'] != $this->app['appid'])<br/><br/>代码解释：<br/><br/>$app['synlogin']是uc应用是否允许同步登录<br/><br/>而且应用id不等于用户当前登录的应用id<br/><br/>$app数组就是uc_server&#92;data&#92;cache&#92;apps.php中的数组$_CACHE['apps']；<br/><br/>$this->app就是用户登录的应用<br/><br/>二、接受其它应用的同步登录通知：<br/><br/>在discuz的api目录下的uc.php中的函数synlogin，在这里接受uc_server发送过来的“同步登录通知”，并设置discuz的cookie，在这个函数中你可以查看到cookie的加密密钥的“算法”；<br/><br/>如果你想看看uc_server发送过的的“通知”是什么数据，你可以这么做：<br/><br/>1,修改要接受通知的应用目录下的api&#92;uc.php，在$action = $get['action'];代码下面添加如下代码：<br/><br/>echo "<pre>";var_dump($get);echo "</pre>";die("<hr>api&#92;uc.php");<br/><br/>2,将上面建立的test.php文件放置在其它允许同步登录的应用目录下，并在浏览器中运行,然后点击页面中对应第一步的应用链接，即可看到uc_server“通知”给改应用的数据；<br/><br/>---------------------------分割线-------------------------------<br/><br/>function synlogin($get, $post)<br/><br/>在这个函数中通过_authcode函数，以密钥$discuz_auth_key加密了cookie；<br/><br/>在这里为了避免cookie名称冲突，在cookie名称（一般为：auth）前加了前缀（$cookiepre)，这个前缀也就是在config.inc.php中设置的那个cookie前缀值；<br/><br/>请看设置cookie的函数_setcookie：<br/><br/>（通过参数$prefix来判断是否对cookie名称添加前缀$cookiepre）<br/><br/>function _setcookie($var, $value, $life = 0, $prefix = 1) &#123;<br/><br/>global $cookiepre, $cookiedomain, $cookiepath, $timestamp, $_SERVER;<br/><br/>setcookie(($prefix ? $cookiepre : '').$var, $value,<br/><br/>&nbsp;&nbsp; $life ? $timestamp + $life : 0, $cookiepath,<br/><br/>&nbsp;&nbsp; $cookiedomain, $_SERVER['SERVER_PORT'] == 443 ? 1 : 0);<br/><br/>&#125;<br/><br/>密钥“算法”：<br/><br/>$discuz_auth_key= md5($_DCACHE['settings']['authkey'].$_SERVER['HTTP_USER_AGENT']);<br/><br/>也就是不同用户加密cookie的密钥可能不同；<br/><br/>三、检查用户是否已登录（无论是那个应用下登录）：<br/><br/>discuz的include目录中common.inc.php中有这样的代码：<br/><br/>$discuz_auth_key = md5($_DCACHE['settings']['authkey'].$_SERVER['HTTP_USER_AGENT']);<br/><br/>list($discuz_pw, $discuz_secques, $discuz_uid) = empty($_DCOOKIE['auth']) ? array('', '', 0) : daddslashes(explode("&#92;t", authcode($_DCOOKIE['auth'], 'DECODE')), 1);<br/><br/>这段代码就是解码在uc.php中用密钥（$discuz_auth_key）加密的cookie值，以获得用户id（$discuz_uid)<br/><br/>这里的解密函数位于bbs&#92;include&#92;global.func.php中，虽然未给函数传递cookie密钥，但函数中通过全局变量$GLOBALS['discuz_auth_key'])获得密钥。<br/>
]]>
</description>
</item><item>
<link>http://www.suibing.com/post/250/</link>
<title><![CDATA[说说ucenter的单点登录 ]]></title> 
<author>suibing &lt;admin@yourname.com&gt;</author>
<category><![CDATA[技术文章]]></category>
<pubDate>Fri, 26 Mar 2010 08:49:41 +0000</pubDate> 
<guid>http://www.suibing.com/post/250/</guid> 
<description>
<![CDATA[ 
	所谓单点登录，无非就是几个站点共用一个用户中心，实现同步登陆，同步退出。<br/><br/>服务器端：Loog SSO （作者:七夜）。<br/><br/>客服端： ucenter，说实话dz商业化确实让php发展了不少。<br/><br/>ucenter 基本原理：<br/><br/>其实最终还是 用户去登录 只是采用了ajax 用户不会发现。<br/><br/>我们来看看和ucenter的具体程序:<br/>config.php<br/><br/>PHP代码<br/>define('UC_CONNECT', 'mysql');&nbsp;&nbsp;&nbsp;&nbsp;// 连接 UCenter 的方式: mysql/NULL, 默认为空时为fscoketopen()&nbsp;&nbsp;&nbsp;&nbsp; <br/>//数据库相关 (mysql 连接时, 并且没有设置 UC_DBLINK 时, 需要配置以下变量)&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('UC_DBHOST', 'localhost');&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// UCenter 数据库主机&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('UC_DBUSER', 'root');&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// UCenter 数据库用户名&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('UC_DBPW', '123');&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// UCenter 数据库密码&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('UC_DBNAME', 'ucenter');&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// UCenter 数据库名称&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('UC_DBCHARSET', 'utf8');&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// UCenter 数据库字符集&nbsp;&nbsp;&nbsp;&nbsp;<br/>define('UC_DBTABLEPRE', 'ucenter.uc_');&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// UCenter 数据库表前缀&nbsp;&nbsp;&nbsp;&nbsp;<br/>define('UC_KEY', 'safefewfef');&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 与 UCenter 的通信密钥, 要与 UCenter 保持一致&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('UC_API', 'http://www.taoav.com/uc');// UCenter 的 URL 地址, 在调用头像时依赖此常量&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('UC_CHARSET', 'utf-8');&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// UCenter 的字符集&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('UC_IP', '127.0.0.1');&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// UCenter 的 IP, 当 UC_CONNECT 为非 mysql 方式时, 并且当前应用服务器解析域名有问题时, 请设置此值&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('UC_APPID', '3');&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 对应到ucenter当前应用的 ID&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('UCDOMAIN','http://www.taoav.com/');&nbsp;&nbsp; //&nbsp;&nbsp;域名设置&nbsp;&nbsp;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>//一些 Cookie 设置&nbsp;&nbsp;&nbsp;&nbsp; <br/>$_UC = array();&nbsp;&nbsp;&nbsp;&nbsp; <br/>$_UC["cookiedomain"] = '';&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // cookie 作用域&nbsp;&nbsp;&nbsp;&nbsp; <br/>$_UC["cookiepath"] = '/';&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// cookie 作用路径&nbsp;&nbsp;&nbsp;&nbsp; <br/>$_UC["cookiepre"] = 'uc_';&nbsp;&nbsp;&nbsp;&nbsp; // cookie 前缀&nbsp;&nbsp;&nbsp;&nbsp; <br/>$_UC["cookietime"] = '31536000';&nbsp;&nbsp;&nbsp;&nbsp;//cookie 作用时间&nbsp;&nbsp;&nbsp;&nbsp; <br/><br/>配置文件写好后，到ucenter后台里面添加一个应用记住是自定义的 ‘UC_KEY’必须和config.php里面相同<br/>接下来就是你的主目录下的api/uc.php<br/>例如应用url 填写为 http://www.taoav.com 那么我就有对应的http://www.taoav.com/api/uc.php<br/>如果要自定义的话 请确认你的对应关系。<br/><br/>最重要的就是api/uc.php ，同步登录就是访问各个应用的uc.php 关于这个dz已经给了demo<br/>developguide<br/><br/> <br/><br/>PHP代码<br/>define('API_DELETEUSER',0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//note 用户删除 API 接口开关&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('API_RENAMEUSER', 0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//note 用户改名 API 接口开关&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('API_GETTAG', 0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//note 获取标签 API 接口开关&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('API_SYNLOGIN', 1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//note 同步登录 API 接口开关&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('API_SYNLOGOUT', 1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//note 同步登出 API 接口开关&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('API_UPDATEPW', 0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//note 更改用户密码 开关&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('API_UPDATEBADWORDS', 0);&nbsp;&nbsp;&nbsp;&nbsp;//note 更新关键字列表 开关&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('API_UPDATEHOSTS', 0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//note 更新域名解析缓存 开关&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('API_UPDATEAPPS', 0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//note 更新应用列表 开关&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('API_UPDATECLIENT', 0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//note 更新客户端缓存 开关&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('API_UPDATECREDIT', 0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//note 更新用户积分 开关&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('API_GETCREDITSETTINGS', 0);&nbsp;&nbsp;&nbsp;&nbsp;//note 向 UCenter 提供积分设置 开关&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('API_GETCREDIT',0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//note 获取用户的某项积分 开关&nbsp;&nbsp;&nbsp;&nbsp; <br/>define('API_UPDATECREDITSETTINGS', 0);&nbsp;&nbsp;&nbsp;&nbsp;//note 更新应用积分设置 开关&nbsp;&nbsp;&nbsp;&nbsp; <br/><br/>这些参数都是向别的应用提供的功能开关<br/><br/>最后关于 自己的页面如何同步登录 别的应用<br/><br/>PHP代码<br/>include_once '../config.php';&nbsp;&nbsp;&nbsp;&nbsp; <br/>include_once '../uc_client/client.php';&nbsp;&nbsp;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>你的验证登录部分&nbsp;&nbsp;&nbsp;&nbsp; <br/>list($uid, $username, $password) = uc_user_login($_POST[username], $_POST[password]);//进入ucenter验证&nbsp;&nbsp;&nbsp;&nbsp; <br/>$ucsynlogin = uc_user_synlogin($uid);//同步登录&nbsp;&nbsp;&nbsp;&nbsp; <br/>echo $ucsynlogin;//因为是ajax 要echo&nbsp;&nbsp;&nbsp;&nbsp; <br/><br/>只用php，康盛的解决方案是比较不错的了，而且利用了p3p头实现了 不同域名 单点登录<br/>缺点就是采用ajax 客服端请求 ，如果有10个以上应用，登录速度就慢下来了。这时候就可以考虑下七夜的Loong SSO<br/>了解了以上的东东 php的CMS和ucenter通信 就不难了<br/><br/>
]]>
</description>
</item><item>
<link>http://www.suibing.com/post/249/</link>
<title><![CDATA[kloxo/lxadmin  安装步骤]]></title> 
<author>suibing &lt;admin@yourname.com&gt;</author>
<category><![CDATA[技术文章]]></category>
<pubDate>Thu, 25 Mar 2010 13:09:47 +0000</pubDate> 
<guid>http://www.suibing.com/post/249/</guid> 
<description>
<![CDATA[ 
	卸载Mysql<br/># rpm -qa &#124; grep mysql<br/><br/>卸载Apache<br/># rpm -qa &#124; grep httpd<br/><br/>卸载PHP<br/># rpm -qa &#124; grep php<br/><br/><br/>wget http://download.lxlabs.com/download/kloxo/production/kloxo-install-master.sh<br/><br/>sh ./kloxo-install-master.sh<br/><br/>yum install php-bcmath php-mhash php-mbstring&nbsp;&nbsp;
]]>
</description>
</item>
</channel>
</rss>