如果权限正确,试着删除cache/tpl/ 里面的文件,应该可以好的
[转载]大流量网站性能优化:一步一步打造一个适合自己的BigRender插件 - 韩子迟 - 博客园
来源: [转载]大流量网站性能优化:一步一步打造一个适合自己的BigRender插件 – 韩子迟 – 博客园
当一个网站越来越庞大,加载速度越来越慢的时候,开发者们不得不对其进行优化,谁愿意访问一个需要等待 10 秒,20 秒才能出现的网页呢?
常见的也是相对简单易行的一个优化方案是 图片的延迟加载。 一个庞大的页面,有时我们并不会滚动去看下面的内容,这样就浪费了非首屏部分的渲染,而这些无用的渲染,不仅包括图片,还包括其他的 DOM 元素,甚至一些 js/css(某些js/css 是根据模块请求的,比如一些 ajax),理论上,每增加一个 DOM,都会增加渲染的时间。有没有办法能使得 HTML、js、css 都能按需加载呢?答案是肯定的,这就是本文要讲的 BigRender。
业界有很多 BigRender 在生产环境中的案例,比如 新浪,美团,途牛旅行网,360网址导航,淘宝商品详情页 等等。查看它们的源代码(ctrl+u),ctrl+f 搜索 textarea 关键字,很容易可以看到一些被 textarea 标签包裹的 HTML 代码。
比如途牛:

而这些被 textarea 标签包裹的 HTML 代码,只是 textarea 的 value 值,并没有渲染到 DOM 树上。没错,BigRender 通常就是用 textarea 标签包裹 HTML 代码(js/css),当作其 value 值,等到合适的时机(通常当 textarea 标签出现或者即将出现在用户视野时)将 textarea 中的 HTML 代码取出,用 innerHTML 动态插入到 DOM 树中,如有必要,取出 js/css 代码(正则),动态执行它们。(是不是和图片的延迟加载很相似?)
玉伯指出:
页面下载完毕后,要经过 Tokenization — Tree Construction — Rendering. 要让首屏尽快出来,得给浏览器减轻渲染首屏的工作量。可以从两方面入手:
1. 减少 DOM 节点数。节点数越少,意味着 Tokenization, Rendering 等操作耗费的时间越少。(对于典型的淘宝商品详情页,经测试发现,每增加一个 DOM 节点,会导致首屏渲染时间延迟约 0.5ms.)
2. 减少脚本执行时间。脚本执行和 UI Update 共享一个 thread, 脚本耗的时间越少,UI Update 就能越发提前。
为什么是用 textarea 标签存放大块 HTML 内容?还是可以看下玉伯的 这篇文章。淘宝的 kissy 就内置了 DataLazyload 组件。(插播:美团详情页还有用到 script 标签做 BigRender 优化,详情请见下面的 “其他” 一节)
接下去就来一步一步实现一个适合自己的 BigRender 插件,我希望可以延迟加载 HTML 元素、js 以及 css。
T.datalazyload
仿照 JQuery 的写法我定义了一个全局对象 T,将延迟加载的实现代码封装在了 T.datalazyload 对象中,将需要延迟加载的代码 “包裹” 在 textarea 标签中,设置其 visibility 属性为 hidden,并赋予该标签一个特殊的类名(为了做事件监听),比如叫做 “datalazyload”。为了方便,我规定每个做 bigrender 优化的 textarea 的父节点都只有一个子孩子(即该 textarea 元素),这一点非常重要必须遵守,因为后面代码有针对此的特殊处理。(注意要设置好父节点的高度宽度,和 dom 渲染后的高度宽度保持一致)
一些 HTML/js/css 代码都可以包裹在 textarea 标签中,例如:
<textarea class="datalazyload" style="visibility: hidden;">
<script type="text/javascript">
alert("I am lazyload zone!");
</script>
<style type="text/css">
.main {margin: 0 auto; text-align: center; padding-top: 200px; width:1000px; height:1000px; border:5px black dashed;}
.second {margin: 0 auto; width:1000px; height:200px; border: 5px purple dotted; padding-top: 100px; text-align: center;}
</style>
<div class="second">
<h1>我是延迟加载的部分!</h1>
</div>
</textarea>
init
给 T.datalazyload 对象定义一个 init() 方法,初始化页面时监听 scroll、resize 以及移动端的 touchmove 事件,当触发这些事件时,回调函数内判断延迟加载部分是否已经出现在视口。
init: function(config) {
var cls = config.cls;
this.threshold = config.threshold ? config.threshold : 0;
this.els = Array.prototype.slice.call(T.getElementsByClassName(cls));
this.fn = this.pollTextareas.bind(this);
this.fn();
T.addEvent(window, "scroll", this.fn);
T.addEvent(window, "resize", this.fn);
T.addEvent(doc.body, "touchMove", this.fn);
}
config 是配置参数,其 cls 属性表示需要延迟加载的 textarea 的类名,threshold 为阈值,单位 px,表示当 textarea 距离视口多少像素时,进行预加载。
将需要延迟加载的元素存入一个数组(this.els),(某 textarea 元素)后续一旦完成加载随即在数组中删除该元素。事件监听的回调函数为 pollTextarea() 方法。
pollTextarea
pollTextareas: function() {
// 需延迟加载的元素已经全部加载完
if (!this.els.length) {
T.removeEvent(window, "scroll", this.fn);
T.removeEvent(window, "resize", this.fn);
T.removeEvent(doc.body, "touchMove", this.fn);
return;
}
// 判断是否需要加载
for (var i = this.els.length; i--; ) {
var ele = this.els[i];
if (!this.inView(ele))
continue;
this.insert(ele);
this.els.splice(i, 1);
}
}
这个方法的作用是判断需要延迟加载的元素是否已经在视口,如果是,则进行加载(触发 insert 方法),并且在数组中删除该元素;如果数组为空,则表明需要延迟加载的部分都已经加载完,移除事件监听,整个延迟加载结束。
insert
接下去看 insert 方法。inert 方法的参数是需要延迟加载的 textarea 元素,很显然,我们需要解析的代码全在 textarea.innerHTML 中。我们用 extractCode 方法取出其中的 js/css 代码,然后将 js/css 过滤掉,这样剩下的就全是 HTML 代码了,将其插入 DOM 中(这正是前文说的 “每个 textarea 的父节点都只有一个子孩子” 的原因,可以直接用父节点 innerHTML 操作),如果有 loading 效果,一般在父节点加个 loading 类,移除即可。最后再动态执行 js 脚本,插入 css 样式。
insert: function(ele) {
var parent = ele.parentNode
, txt = this.decodeHTML(ele.innerHTML)
, matchStyles = this.extractCode(txt, true)
, matchScripts = this.extractCode(txt);
parent.innerHTML = txt
.replace(new RegExp("<script[^>]*>([\\S\\s]*?)</script\\s*>", "img"), "")
.replace(new RegExp("<style[^>]*>([\\S\\s]*?)</style\\s*>", "img"), "");
if (matchStyles.length)
for (var i = matchStyles.length; i --;)
this.evalStyles(matchStyles[i]);
// 如果延迟部分需要做 loading 效果
parent.className = parent.className.replace("loading", "");
if (matchScripts.length)
for (var i = 0, len = matchScripts.length; i < len; i++)
this.evalScripts(matchScripts[i]);
},
extractCode
我们通过正则将 js 和 css 标签部分取出:
extractCode: function(str, isStyle) {
var cata = isStyle ? "style" : "script"
, scriptFragment = "<" + cata + "[^>]*>([\\S\\s]*?)</" + cata + "\\s*>"
, matchAll = new RegExp(scriptFragment, "img")
, matchOne = new RegExp(scriptFragment, "im")
, matchResults = str.match(matchAll) || []
, ret = [];
for (var i = 0, len = matchResults.length; i < len; i++) {
var temp = (matchResults[i].match(matchOne) || [ "", "" ])[1];
temp && ret.push(temp);
}
return ret;
}
成功地将 script 以及 style 标签内的内容提取了出来,巧妙地用了正则中的子表达式。
evalScripts/evalStyles
脚本执行,样式渲染。
evalScripts: function(code) {
var head = doc.getElementsByTagName("head")[0]
, js = doc.createElement("script");
js.text = code;
head.insertBefore(js, head.firstChild);
head.removeChild(js);
},
evalStyles: function(code) {
var head = doc.getElementsByTagName("head")[0]
, css = doc.createElement("style");
css.type = "text/css";
try {
css.appendChild(doc.createTextNode(code));
} catch (e) {
css.styleSheet.cssText = code;
}
head.appendChild(css);
}
优缺点 & 适用场景
简单讲讲 BigRender 优化的优缺点,以及适用场景。
优点很明显,因为减少了首屏 DOM 的渲染,所以能加快首屏加载的速度,并且能分块加载 js/css,非常适用于一些模块区分度很高的网站(个人觉得大型网站的模块区分度普遍越来越高了)。
缺点是需要更改 DOM 结构(DOM 节点的替换和渲染),可能会引起一些重排和重绘。一些没有开启 js 功能的用户将看不到延迟加载的内容(可以用 noscript 标签给出一个善意提醒)。最大的缺点可能是不利于 SEO,一些依赖于 SEO 的网站可能需要在 SEO 上下点功夫了,比如美团。
关于 SEO,可以看下 http://www.seoqx.com/lynx 这个网站,能模拟搜索引擎蜘蛛对网站的爬取情况。美团对于 BigRender 以及 SEO 解决方案 [美团网案例]改善BigRender技术导致的SEO问题
bigrender 通过减少 DOM 节点,加快首屏的渲染,但是,它也是有额外的性能损耗的,渲染前textarea 里面的 html 代码,在服务端把 html 代码保存在隐藏的 textarea 里面,所以在服务端会把 html 代码转义:尖括号等都被转义了,这个会增加服务器的压力;而且,这个改造只是前端的渲染,服务器依旧是一次计算所有的数据,输出所有的数据,这一点没有得到提高。
一般来说,使用都是后端拼接成 html 字符串,然后塞入 textarea 标签中,吐给前端。
demo
如果要做一个完整的 BigRender demo,可能比较复杂,还要涉及到后端。
之前学习 lazyload 时做过一个图片的延迟加载 demo,see http://hanzichi.github.io/cnblogs/2016/Feb/picture-lazyload/。因为 BigRender 是 lazyload 的加强版,所以简单地做了个 BigRender 版本的图片延迟加载 http://hanzichi.github.io/cnblogs/2016/Mar/bigrender/,实现的具体代码可以 check bigrender.js。
其他
除了首页部分用了 textarea 做 BigRender 优化外,美团还用到了 script 标签做优化。比如 这个商品详情页

给 script 标签设置个非 “text/JavaScript” 的 type,可以下载这段 js,但不执行,这种做法似曾相识,在 labjs 中看到过。
更多可以参考 前端优化三续:用script存放html代码来减少DOM节点数
Read More
[转载]使用nodejs爬取拉勾苏州和上海的.NET职位信息 - Agile.Zhou(kklldog) - 博客园
来源: [转载]使用nodejs爬取拉勾苏州和上海的.NET职位信息 – Agile.Zhou(kklldog) – 博客园
最近开始找工作,本人苏州,面了几家都没有结果很是伤心。在拉勾上按照城市苏州关键 字.NET来搜索一共才80来个职位,再用薪水一过滤,基本上没几个能投了。再加上最近苏州的房价蹭蹭的长,房贷压力也是非常大,所以有点想往上海去发 展。闲来无聊写了个小爬虫,爬了下苏州跟上海的.NET职位的信息,然后简单对比了一下。
是的小弟擅长.NET,为啥用nodejs?因为前几天有家公司给了个机会可以转nodejs,所以我是用来练手的,不过后来也泡汤了,但是还是花两晚写完了。刚学,代码丑轻喷哈!
一:如何爬取拉勾的数据
这个其实非常简单,本来还以为要用正则去分析html,其实拉勾分页提了ajax的接口,可以直接用http去访问。打开神器Chrome的F12一看便知。
这是用nodejs模拟分页请求的代码:
var getData = function (kd,city,pn) {
var mongo = require('./mongo');
var http = require('http');
var queryString = require('querystring');
var postData=queryString.stringify({
'pn':pn,
'kd':kd,
'first':false
});
var options = {
hostname:'www.lagou.com',
method:'POST',
path:'/jobs/positionAjax.json?px=default&city='+city,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
}
};
var postResult = '';
var req = http.request(options,(res)=>{
console.log(`STATUS:${res.statusCode}`);
res.setEncoding('utf8');
res.on('data',(chunk)=>{
postResult+=chunk;
});
res.on('end',()=>{
console.log(`RESULT:${postResult}`);
var jsonObj =JSON.parse(postResult);
//insert into db
jsonObj.content.result.forEach((item)=>{
var salary = item.salary;
//拆分3k-6k,易于统计
var arr = salary.split('-');
var min = arr[0].substring(0,arr[0].indexOf('k'));
var max = arr.length>1? arr[1].substring(0,arr[1].indexOf('k')):min;
item.salaryMin = parseInt(min);
item.salaryMax = parseInt(max);
mongo.save(city,item);
});
if(jsonObj.content.hasNextPage&&jsonObj.content.totalPageCount>pn){
getData(kd,city,pn+1);
}
});
req.on('error',(e)=>{
console.log(`problem with request:${e.message}`);
});
});
req.write(postData);
req.end();
console.log(`start to get data. pn:${pn} city:${city} kd:${kd}`);
};
exports.run = getData;
二:数据存储在哪里
拉勾的分页接口返回的是json对象,那么自然是存mongoDb最简单了。
下面是mongoDb的封装:
var save=function (city,jsonObj) {
var Db = require('mongodb').Db;
var Server = require('mongodb').Server;
var db = new Db('test',new Server('localhost',27017))
db.open((err,db)=>{
var coll = db.collection(city);
coll.save(jsonObj,(err,r)=>{
if(!err){
console.log('save to '+city);
}
db.close();
});
});
};
var removeAll = function (city,callback) {
var Db = require('mongodb').Db;
var Server = require('mongodb').Server;
var db = new Db('test',new Server('localhost',27017))
db.open((err,db)=>{
var coll = db.collection(city);
coll.remove((err,numOfRows)=>{
if(!err){
console.log(`${city} collection be removed. ${numOfRows}`);
}
db.close();
callback(err);
});
});
};
var readAll=function (city,callback) {
var Db = require('mongodb').Db;
var Server = require('mongodb').Server;
var db = new Db('test',new Server('localhost',27017))
db.open((err,db)=>{
var coll = db.collection(city);
var cursor = coll.find();
cursor.toArray((err,results)=>{
if(!err){
callback(results);
//db.close();
}
db.close();
});
});
}
exports.save = save;
exports.removeAll = removeAll;
exports.readAll = readAll;
三:如何展示数据
使用nodejs自带的httpServer,接受到请求的时候直接读取一个html文件,然后把对比的信息填入html文本里,用一个h5的chart来展示
下面是服务器的代码:
var http = require('http');
var fs = require('fs');
var stati = require('./statistics');
var szStati = {text:'SuZhou'};
var shStati = {text:'ShangHai'};
var server=new http.Server();
server.on('request',function(req,res){
res.writeHead(200,{'Content-Type':'text/html'});
fs.readFile('./index.html','utf8',(err,data)=>{
if (err) {
throw err;
}
console.log(data);
// res.write(data);
// res.end();
stati.statiSalary('苏州',(results)=>{
szStati.values = results;
stati.statiSalary('上海',(results)=>{
shStati.values = results;
var series =[szStati,shStati];
var strSeries = JSON.stringify(series);
console.log(strSeries);
data = data.replace('@series',strSeries);
console.log(data);
res.write(data);
res.end();
});
});
});
});
server.listen(3000);
console.log('http server started...port:3000');
四:统计结果

统计按照 0-5k,5-10k,10-15k,15-20k,20-25k,>25k这几个区间按照职位的数量进行统计。
0-5k:上海是苏州的4倍
5-10k:上海是苏州的4倍
10-15k:上海是苏州的9倍
15-20k:上海是苏州的12倍
20-25k:上海是苏州的17倍
>25k:上海是苏州的26倍
可以看到从10-15k开始的职位,上海的数量是苏州的10多倍,越是高薪的职位倍数越高。由此可以看出,苏州跟上海的差距还是非常大的。苏州政府 一直沾沾自喜,觉得自己在互联网圈子有多牛逼,搞了一堆孵化器,但其实拿的出手的公司有几家呢,一只手都数过来了,跟北上广深一线还是差的很远呢,还是要 努力啊。
恐怕我也要背井离乡去上海的寻找未来了。
还没学会用VS Code上传到github上,先直接上传代码吧:lagouSpider.zip
[转载]微信企业付款开发 C# - LLorJJ999 - 博客园
来源: [转载]微信企业付款开发 C# – LLorJJ999 – 博客园
一、第一步:需要准备的东东
<add key=”sAppID” value=”wxf2303b260*******”/> // 开发者应用ID ,如图一
<add key=”sAppSecret” value=”5b83018b0b69c4231c14a2a25*******”/> //开发者应用密钥,如图一
<add key=”sPartnerKey” value=”E07D38C4EC0C9B42BF808633*******”/> //商户秘钥 如图二
<add key=”sPartner” value=”**********”/> // 商户号 申请微信支付通过后,收到的邮件里面有, 10位的商户号
(图一),登录地址:https://mp.weixin.qq.com/

(图二,你自己设置的32位秘钥),登录地址:https://pay.weixin.qq.com/index.php/home/login?return_url=%2F
二、第二步:安装证书,windows下面选择.p12格式的证书;取证书时一定得用 绝对路径(如:D:\wwwroot\BusinessCard\weixin\businesscard\cert\apiclient_cert.p12)
证书pkcs12格式 (apiclient_cert.p12)
三、第三步:帐户里面必须有钱,如下图

四、第四步:源码如下:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Web;
namespace BusinessCard.Web.Code
{
public class Class1
{
/// <summary>
/// 企业付款给个人,直接入帐到微信钱包中
/// </summary>
public static string TENPAY = "1";
public static string APPID = Vincent._WebConfig.GetAppSettingsString("sAppID"); //开发者应用ID
public static string PARTNER = Vincent._WebConfig.GetAppSettingsString("sPartner"); //商户号
public static string APPSECRET = Vincent._WebConfig.GetAppSettingsString("sAppSecret"); //开发者应用密钥
public static string PARTNER_KEY = Vincent._WebConfig.GetAppSettingsString("sPartnerKey"); //商户秘钥
public const string URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
//服务器异步通知页面路径(流量卡)
public static string WebUrl = Vincent._WebConfig.GetAppSettingsString("WebUrl");
public static readonly string NOTIFY_URL_Card_Store = "http://" + WebUrl + "/weixinpay/WXPayNotify_URL.aspx";// ConfigurationManager.AppSettings["WXPayNotify_URL_CardStore"].ToString();
public static readonly string NOTIFY_URL_Card_User = "http://" + WebUrl + "/weixinpay/WXPayNotify_URL.aspx"; //ConfigurationManager.AppSettings["WXPayNotify_URL_CardUser"].ToString();
public static readonly string NOTIFY_URL_HB_Store = "http://" + WebUrl + "/weixinpay/WXPayNotify_URL.aspx";// ConfigurationManager.AppSettings["WXPayNotify_URL_CardStore"].ToString();
//=======【代理服务器设置】===================================
/* 默认IP和端口号分别为0.0.0.0和0,此时不开启代理(如有需要才设置)
*/
public const string PROXY_URL = "http://10.152.18.220:8080";
//=======【证书路径设置】=====================================
/* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要)
*/
public const string SSLCERT_PATH = "weixin\\businesscard\\cert\\apiclient_cert.p12";
public static string SSLCERT_PASSWORD = PARTNER;
/// <summary>
/// 企业付款给个人
/// </summary>
/// <returns></returns>
public static string EnterprisePay(string Bill_No, string toOpenid, decimal Charge_Amt, string userName, string title)
{
//公众账号appid mch_appid 是 wx8888888888888888 String 微信分配的公众账号ID(企业号corpid即为此appId)
//商户号 mchid 是 1900000109 String(32) 微信支付分配的商户号
//设备号 device_info 否 013467007045764 String(32) 微信支付分配的终端设备号
//随机字符串 nonce_str 是 5K8264ILTKCH16CQ2502SI8ZNMTM67VS String(32) 随机字符串,不长于32位
//签名 sign 是 C380BEC2BFD727A4B6845133519F3AD6 String(32) 签名,详见签名算法
//商户订单号 partner_trade_no 是 10000098201411111234567890 String 商户订单号,需保持唯一性
//用户openid openid 是 oxTWIuGaIt6gTKsQRLau2M0yL16E String 商户appid下,某用户的openid
//校验用户姓名选项 check_name 是 OPTION_CHECK String NO_CHECK:不校验真实姓名
//FORCE_CHECK:强校验真实姓名(未实名认证的用户会校验失败,无法转账)
//OPTION_CHECK:针对已实名认证的用户才校验真实姓名(未实名认证用户不校验,可以转账成功)
//收款用户姓名 re_user_name 可选 马花花 String 收款用户真实姓名。
// 如果check_name设置为FORCE_CHECK或OPTION_CHECK,则必填用户真实姓名
//金额 amount 是 10099 int 企业付款金额,单位为分
//企业付款描述信息 desc 是 理赔 String 企业付款操作说明信息。必填。
//Ip地址 spbill_create_ip 是 192.168.0.1 String(32) 调用接口的机器Ip地址
Bill_No = PARTNER + getTimestamp() + Bill_No; //订单号组成 商户号 + 随机时间串 + 记录ID
//设置package订单参数
SortedDictionary<string, string> dic = new SortedDictionary<string, string>();
string total_fee = (Charge_Amt * 100).ToString("f0");
string wx_nonceStr = Guid.NewGuid().ToString().Replace("-", ""); //Interface_WxPay.getNoncestr();
dic.Add("mch_appid", APPID);
dic.Add("mchid", PARTNER);//财付通帐号商家
//dic.Add("device_info", "013467007045711");//可为空
dic.Add("nonce_str", wx_nonceStr);
dic.Add("partner_trade_no", Bill_No);
dic.Add("openid", toOpenid);
dic.Add("check_name", "NO_CHECK");
dic.Add("amount", total_fee);
dic.Add("desc", title);//商品描述
dic.Add("spbill_create_ip", "211.149.234.224"); //用户的公网ip,不是商户服务器IP
//生成签名
string get_sign = BuildRequest(dic, PARTNER_KEY);
Vincent._Log.SaveMessage("第一步 get_sign:" + get_sign);
string _req_data = "<xml>";
_req_data += "<mch_appid>" + APPID + "</mch_appid>";
_req_data += "<mchid>" + PARTNER + "</mchid>";
_req_data += "<nonce_str>" + wx_nonceStr + "</nonce_str>";
_req_data += "<partner_trade_no>" + Bill_No + "</partner_trade_no>";
_req_data += "<openid>" + toOpenid + "</openid>";
_req_data += "<check_name>NO_CHECK</check_name>";
_req_data += "<amount>" + total_fee + "</amount>";
_req_data += "<desc>" + title + "</desc>";
_req_data += "<spbill_create_ip>211.149.234.224</spbill_create_ip>";
_req_data += "<sign>" + get_sign + "</sign>";
_req_data += "</xml>";
Vincent._Log.SaveMessage("企业付款生成的xml:" + _req_data.Trim());
var result = HttpPost(URL, _req_data.Trim(), true, 300);
//var result = HttpPost(URL, _req_data, Encoding.UTF8);
Vincent._Log.SaveMessage("返回结果:" + result);
return result;
//ReturnValue retValue = StreamReaderUtils.StreamReader(URL, Encoding.UTF8.GetBytes(_req_data), System.Text.Encoding.UTF8, true);
//Vincent._Log.SaveMessage("返回结果:" + retValue.ErrorCode);
//return retValue.ErrorCode;
}
public static string getTimestamp()
{
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToInt64(ts.TotalSeconds).ToString();
}
public static string BuildRequest(SortedDictionary<string, string> sParaTemp, string key)
{
//获取过滤后的数组
Dictionary<string, string> dicPara = new Dictionary<string, string>();
dicPara = FilterPara(sParaTemp);
//组合参数数组
string prestr = CreateLinkString(dicPara);
//拼接支付密钥
string stringSignTemp = prestr + "&key=" + key;
Vincent._Log.SaveMessage("生成签名的参数:" + stringSignTemp);
//获得加密结果
string myMd5Str = GetMD5(stringSignTemp.Trim());
//返回转换为大写的加密串
return myMd5Str.ToUpper();
}
/// <summary>
/// 除去数组中的空值和签名参数并以字母a到z的顺序排序
/// </summary>
/// <param name="dicArrayPre">过滤前的参数组</param>
/// <returns>过滤后的参数组</returns>
public static Dictionary<string, string> FilterPara(SortedDictionary<string, string> dicArrayPre)
{
Dictionary<string, string> dicArray = new Dictionary<string, string>();
foreach (KeyValuePair<string, string> temp in dicArrayPre)
{
if (temp.Key != "sign" && !string.IsNullOrEmpty(temp.Value))
{
dicArray.Add(temp.Key, temp.Value);
}
}
return dicArray;
}
//组合参数数组
public static string CreateLinkString(Dictionary<string, string> dicArray)
{
StringBuilder prestr = new StringBuilder();
foreach (KeyValuePair<string, string> temp in dicArray)
{
prestr.Append(temp.Key + "=" + temp.Value + "&");
}
int nLen = prestr.Length;
prestr.Remove(nLen - 1, 1);
return prestr.ToString();
}
//加密
public static string GetMD5(string pwd)
{
MD5 md5Hasher = MD5.Create();
byte[] data = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(pwd));
StringBuilder sBuilder = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
return sBuilder.ToString();
}
public static string HttpPost(string postUrl, string paramData, Encoding dataEncode)
{
string ret = string.Empty;
try
{
byte[] byteArray = dataEncode.GetBytes(paramData); //转化
HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(new Uri(postUrl));
webReq.Method = "POST";
webReq.ContentType = "application/x-www-form-urlencoded";
webReq.ContentLength = byteArray.Length;
Stream newStream = webReq.GetRequestStream();
newStream.Write(byteArray, 0, byteArray.Length);//写入参数
newStream.Close();
HttpWebResponse response = (HttpWebResponse)webReq.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.Default);
ret = sr.ReadToEnd();
sr.Close();
response.Close();
newStream.Close();
}
catch (Exception ex)
{
Vincent._Log.SaveMessage("Post提交异常:" + ex.Message);
}
return ret;
}
public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
//直接确认,否则打不开
return true;
}
/// <summary>
/// post提交支付
/// </summary>
/// <param name="xml"></param>
/// <param name="url"></param>
/// <param name="isUseCert">是否使用证书</param>
/// <param name="timeout"></param>
/// <returns></returns>
public static string HttpPost(string url, string xml, bool isUseCert, int timeout)
{
System.GC.Collect();//垃圾回收,回收没有正常关闭的http连接
string result = "";//返回结果
HttpWebRequest request = null;
HttpWebResponse response = null;
Stream reqStream = null;
try
{
//设置最大连接数
ServicePointManager.DefaultConnectionLimit = 200;
//设置https验证方式
if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
{
ServicePointManager.ServerCertificateValidationCallback =
new RemoteCertificateValidationCallback(CheckValidationResult);
}
/***************************************************************
* 下面设置HttpWebRequest的相关属性
* ************************************************************/
request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.Timeout = timeout * 1000;
//设置代理服务器
//WebProxy proxy = new WebProxy(); //定义一个网关对象
//proxy.Address = new Uri(PROXY_URL); //网关服务器端口:端口
//request.Proxy = proxy;
//设置POST的数据类型和长度
request.ContentType = "text/xml";
byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
request.ContentLength = data.Length;
//是否使用证书
if (isUseCert)
{
string path = HttpContext.Current.Request.PhysicalApplicationPath;
//X509Certificate2 cert = new X509Certificate2(path + SSLCERT_PATH, SSLCERT_PASSWORD);
//将上面的改成
X509Certificate2 cert = new X509Certificate2(path + SSLCERT_PATH, SSLCERT_PASSWORD, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);//线上发布需要添加
request.ClientCertificates.Add(cert);
Vincent._Log.SaveMessage("证书路径:" + (path + SSLCERT_PATH));
//Vincent._Log.SaveMessage("WxPayApi:PostXml used cert");
}
//往服务器写入数据
reqStream = request.GetRequestStream();
reqStream.Write(data, 0, data.Length);
reqStream.Close();
//获取服务端返回
response = (HttpWebResponse)request.GetResponse();
//获取服务端返回数据
StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
result = sr.ReadToEnd().Trim();
sr.Close();
}
catch (System.Threading.ThreadAbortException e)
{
Vincent._Log.SaveMessage("HttpService:Thread - caught ThreadAbortException - resetting.");
Vincent._Log.SaveMessage("Exception message:" + e.Message);
System.Threading.Thread.ResetAbort();
}
catch (WebException e)
{
Vincent._Log.SaveMessage("HttpService" + e.ToString());
if (e.Status == WebExceptionStatus.ProtocolError)
{
Vincent._Log.SaveMessage("HttpService:StatusCode : " + ((HttpWebResponse)e.Response).StatusCode);
Vincent._Log.SaveMessage("HttpService:StatusDescription : " + ((HttpWebResponse)e.Response).StatusDescription);
}
throw new Exception(e.ToString());
}
catch (Exception e)
{
Vincent._Log.SaveMessage("HttpService" + e.ToString());
throw new Exception(e.ToString());
}
finally
{
//关闭连接和流
if (response != null)
{
response.Close();
}
if (request != null)
{
request.Abort();
}
}
return result;
}
/// <summary>
/// 处理http GET请求,返回数据
/// </summary>
/// <param name="url">请求的url地址</param>
/// <returns>http GET成功后返回的数据,失败抛WebException异常</returns>
public static string Get(string url)
{
System.GC.Collect();
string result = "";
HttpWebRequest request = null;
HttpWebResponse response = null;
//请求url以获取数据
try
{
//设置最大连接数
ServicePointManager.DefaultConnectionLimit = 200;
//设置https验证方式
if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
{
ServicePointManager.ServerCertificateValidationCallback =
new RemoteCertificateValidationCallback(CheckValidationResult);
}
/***************************************************************
* 下面设置HttpWebRequest的相关属性
* ************************************************************/
request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
//设置代理
WebProxy proxy = new WebProxy();
proxy.Address = new Uri(PROXY_URL);
request.Proxy = proxy;
//获取服务器返回
response = (HttpWebResponse)request.GetResponse();
//获取HTTP返回数据
StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
result = sr.ReadToEnd().Trim();
sr.Close();
}
catch (System.Threading.ThreadAbortException e)
{
Vincent._Log.SaveMessage("HttpService:Thread - caught ThreadAbortException - resetting.");
Vincent._Log.SaveMessage("Exception message: " + e.Message);
System.Threading.Thread.ResetAbort();
}
catch (WebException e)
{
Vincent._Log.SaveMessage("HttpService" + e.ToString());
if (e.Status == WebExceptionStatus.ProtocolError)
{
Vincent._Log.SaveMessage("HttpService:StatusCode : " + ((HttpWebResponse)e.Response).StatusCode);
Vincent._Log.SaveMessage("HttpService:StatusDescription : " + ((HttpWebResponse)e.Response).StatusDescription);
}
throw new Exception(e.ToString());
}
catch (Exception e)
{
Vincent._Log.SaveMessage("HttpService" + e.ToString());
throw new Exception(e.ToString());
}
finally
{
//关闭连接和流
if (response != null)
{
response.Close();
}
if (request != null)
{
request.Abort();
}
}
return result;
}
}
}
[转载]零OCR基础6行代码实现C#验证码识别 - Я!ńɡ - 博客园
来源: [转载]零OCR基础6行代码实现C#验证码识别 – Я!ńɡ – 博客园
这两天因为工作需要,要到某个网站采集信息,一是要模拟登陆,二是要破解验证码,本想用 第三方付费打码,但是想想网上免费的代码也挺多的,于是乎准备从网上撸点代码下来,谁知道,撸了好多个都不行,本人以前也没接触过这方面的,代码无从下 手,最后不知道在哪个兄台博客找到一个国外的第三方开源OCR,说是强大的谷歌公司做维护,C++开发的,有.NET封装的链接库,甚好!
项目地址:https://github.com/tesseract-ocr/tesseract
语言库:https://github.com/tesseract-ocr/langdata
OCR语言训练:https://github.com/tesseract-ocr/tessdata
下面开始撸示例:
新建C#控制台,版本选择.NET 4.5
Tesseract ocr = new Tesseract();
ocr.SetVariable("tessedit_char_whitelist", "0123456789");
ocr.Init(@"D:\测试\Ocr\tessdata", "eng", true);
第一句就不用说了,第二句是设置识别的字符,例如,如果你要识别的验证码是A-Z0-9你就都写进来就OK了
第三句就是初始化OCR的语言训练配置,里面很多文件,只要写文件名小数点前面的就OK了
List<Word> result = ocr.DoOCR(bmp, Rectangle.Empty); if(result.Count<=0)return; string code = result[0].Text;
最后的Code就是识别出来的验证码了,这里验证码图片一定要转换为Bitmap对象才行,记得用完了释放Bitmap对象!
下面是我测试截图:

上面是验证码,下面文件名是识别出来的结果命名保存的文件!当然验证码是经过处理的,原始的验证码图片是酱紫的:
验证码图片太小,OCR识别不了,而且默认情况下,要是白底,黑子才能识别,所以网上的验证码一定要先自己二值化处理并且清除掉背景色,再进行识别!
我这里的处理方式是二值化之后,把图片放大三倍,不要担心看着有锯齿,OCR可以识别的
当初我把图片放大两倍,发现有的时候8会被识别成3,所以我干脆又放大了一倍,发现不存在这个问题了,虽然看起来锯齿感很明显,但是OCR不管美丑
你是不是参照案例撸码了,运行了?然后你发现程序运行报错了?
这里要在程序的app.config的startup节点加上 useLegacyV2RuntimeActivationPolicy=”true”节点,详细如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
然后再运行,是不是可以识别出来了,就是这么简单!
[转载][PHP]利用XAMPP搭建本地服务器, 然后利用iOS客户端上传数据到本地服务器中(三. PHP端代码实现) - M_Lee - 博客园
来源: [转载][PHP]利用XAMPP搭建本地服务器, 然后利用iOS客户端上传数据到本地服务器中(三. PHP端代码实现) – M_Lee – 博客园
一.安装XAMPP http://www.cnblogs.com/lidongxu/p/5256330.html
二. 配置MySQL http://www.cnblogs.com/lidongxu/p/5256515.html
然后呢, 今天我们就来接触下PHP开发语言
1. 首先呢, 需要在我们本机服务器文件夹资源下新建个.php文件, 废话嘛(你要写php啦!)

2. 在register.php 输入以下代码
<?php
// 1. 获取客户端利用post方式网络请求的body里的字段对应的value (这个字段
// 是这里规定的, 前端必须遵守这个name2, pass2等key值)
$nameP = $_POST['name2'];
$passP = $_POST['pass2'];
$ageP = $_POST['age2'];
$telephoneP = $_POST['telephone2'];
// 2. 建立数据库连接 (127.0.0.1 数据库所在的ip地址)
// root 是数据库用户名(默认的)
// "" 密码(默认是空)
$con = mysql_connect("127.0.0.1", "root", "");
$myCon = mysql_select_db("lidongxu", $con);
// 3. 先查询, 如果存在就不要在插入了
$select = "select userName from User where userName = '$nameP'";
$seleResult = mysql_query($select);
// 4. 如果查到了, 说明已经存在这个用户了, 则返回-1给客户端代表已经注册过了
if (mysql_num_rows($seleResult)) {
// success 就是key值 对应的value 就是后面的字符串
$a = array();
$a['success'] = "-1";
$a['status'] = "have";
$arr = json_encode($a);
echo $arr;
}
// 5. 如果没注册过, 那么
else {
// 6. 把数据都插入到mysql数据库中
$sql = "insert into User values('$nameP', '$passP', '$ageP', '$telephoneP')";
$result = mysql_query($sql);
if ($result == 1) { // 7. 代表执行成功
$a = array();
$a['success'] = "1";
$a['status'] = "ok";
$arr = json_encode($a);
echo $arr;
}
else { // 8. 代表插入失败
$a = array();
$a['success'] = "0";
$a['status'] = "no";
$arr = json_encode($a);
echo $arr;
}
}
// 9. 接收用户头像图片
// 9.1. 接收图片传到服务器上默认的临时文件路径以及名字 (uploadfile 给前台使用的
// 字段)
$url = $_FILES["uploadimageFile"]["tmp_name"];
// 9.2 获取根路径下的downloads文件夹下的路径(download2 需要手动
// 去本地创建)
$destination_folder = $_SERVER['DOCUMENT_ROOT'].'/download2/';
// 9.3拼接要作为服务器上保存的文件名字
$newfname = $destination_folder .(string)$nameP.'.jpg'; //set your file ext
// 打开连接 rb+ 读写打开一个二进制文件,允许读写数据,文件必须存在。
// 获取客户端上传到缓存文件夹下的文件
$file = fopen ($url, "rb");
if ($file) {
// a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。
// 获取要把客户端传递过来的文件复制到新的文件夹下的名字
$newf = fopen ($newfname, "a");
if ($newf)
// 检查文件是否结束,如结束,则返回非零值
while(!feof($file)) {
// 开始从某个文件读取1MB 然后写入到新的路径1MB
fwrite($newf, fread($file, 1024 * 8 ), 1024 * 8 );
}
}
if ($file) {
// 关闭文件链接
fclose($file);
}
if ($newf) {
fclose($newf);
}
?>
3. 然后在本地服务器文件夹下新建download2文件夹

4. 然后再把登录的php代码也写了吧!在htdocs文件夹下, 新建loginGet.php文件 然后插入代码
<?php
// 1. 获取GET网络请求网址里的key值对应的value
// 声明变量name1 和pass1 接收
$name1 = $_GET['name'];
$pass1 = $_GET['pass'];
// 2. 建立数据库连接
// 参数1: 数据库所在的服务器的地址(本机127.0.0.1或者localhost)
// 参数2: MySql数据库的账户(默认root)
// 参数3: MySql数据库的密码(默认无)
$con = mysql_connect("127.0.0.1", "root", "");
// 参数1: 自己建立的数据库的名字
$myCon = mysql_select_db("lidongxu", $con);
// 3. 执行查询 (利用用户名和密码进行匹配查找, 如果找到了随意返回userName(用户名))
$sql = "select * from User where userName = '$name1' And password = '$pass1'";
// 4. 接收结果
$result = mysql_query($sql);
// 4.2 如果查询结果为空的话
if(mysql_num_rows($result) == 0) {
$a = array();
$a['success'] = "0";
$a['name'] = "null";
$a['status'] = "no";
$arr = json_encode($a);
echo $arr;
}
else {
// 5. 取出本条记录
$row = mysql_fetch_row($result);
$a = array();
$a['success'] = "1";
$a['name'] = $row[0];
$a['age'] = $row[2];
$a['telephone'] = $row[3];
$a['status'] = "ok";
$arr = json_encode($a);
echo $arr;
}
?>
到此, php暂时告一段路, 然后进行iOS段代码开发(开心不???)
来写iOS 代码吧……….. http://www.cnblogs.com/lidongxu/p/5267753.html
[转载]Linux下安装SVN服务端小白教程 - 六仙庵 - 博客园
来源: [转载]Linux下安装SVN服务端小白教程 – 六仙庵 – 博客园
安装
使用yum安装非常简单:
yum install subversion
配置
创建仓库
我们这里在/home下建立一个名为svn的仓库(repository),以后所有代码都放在这个下面,创建成功后在svn下面多了几个文件夹。
[root@localhost /]# cd /home
[root@localhost home]# mkdir svn
[root@localhost home]# svnadmin create /home/svn
[root@localhost home]# ls svn
conf db format hooks locks README.txt
我们这里特别关注一下conf文件夹,这个是存放配置文件的
[root@localhost home]# cd svn/conf
[root@localhost conf]# ls
authz passwd svnserve.conf
其中:
- authz 是权限控制文件
- passwd 是帐号密码文件
- svnserve.conf 是SVN服务配置文件
接下来我们依次修改这3个文件。
配置passwd
[root@localhost conf]# vi passwd
[users]
test1=123456
test2=123456
上面的例子中我们创建了2个用户,一个test1,一个test2

配置authz
[root@localhost conf]# vi authz
[/]
liuxianan=rw
test1=r
test2=r
*=
上面配置的含义是,liuxianan对/home/svn/下所有文件具有可读可写权限,test只有只读权限,除此之外,其它用户均无任何权限,最后一行*=很重要不能少。

拓展:使用用户分组
这个我一般不用,但是记录下来。
还是这个文件:
[root@localhost conf]# vi authz
[groups]
group1 = liuxianan
group2 = test1,test2
[/]
@group1 = rw
@group2 = r
* =
上面配置中创建了2个分组,分组1的用户可读可写,分组2的用户只读。
格式说明:
版本库目录格式:
[<版本库>:/项目/目录]
@<用户组名> = <权限>
<用户名> = <权限>
配置svnserve.conf
[root@localhost conf]# vi svnserve.conf
打开下面的5个注释
anon-access = read #匿名用户可读
auth-access = write #授权用户可写
password-db = passwd #使用哪个文件作为账号文件
authz-db = authz #使用哪个文件作为权限文件
realm = /home/svn # 认证空间名,版本库所在目录
2点注意:
- 最后一行的realm记得改成你的svn目录
- 打开注释时切记前面不要留有空格,否则可能有问题(网上说的,我没有亲测)

启动与停止
[root@localhost conf]# svnserve -d -r /home/svn(启动)
[root@localhost conf]#killall svnserve(停止)
上述启动命令中,-d表示守护进程, -r 表示在后台执行。停止还可以采用杀死进程的方式:
[root@localhost conf]# ps -ef|grep svnserve
root 4908 1 0 21:32 ? 00:00:00 svnserve -d -r /home/svn
root 4949 4822 0 22:05 pts/0 00:00:00 grep svnserve
[root@localhost conf]# kill -9 4908

最后来个总的截图:

客户端连接
这里使用TortoiseSVN,输入地址svn://你的IP 即可,不出意外输入用户名和密码就能连接成功了。
默认端口3690,如果你修改了端口,那么要记得加上端口号。

总结
总的来说,如果你不需要杂七杂八的权限配置只是自己一个人用的话,安装配置还是比较简单的,并不像网上说的那么麻烦,我按照网上的方法一次性成功了。
扩展:yum安装路径
以svn为例:
# rpm -qa | grep subversion
subversion-1.6.11-15.el6_7.x86_64
# rpm -ql subversion-1.6.11-15.el6_7.x86_64
...
/usr/share/doc/subversion-1.6.11
/usr/share/doc/subversion-1.6.11/BUGS
/usr/share/doc/subversion-1.6.11/CHANGES
...
说明:
- rpm -qa 查询所有安装的rpm包,可以配合grep命令。
- rpm -qi 查询某个具体包的介绍。
- rpm -ql 列出某个具体包的所有文件
rpm几个默认安装路径:
/etc 一些设置文件放置的目录
/usr/bin 一些可执行文件
/usr/lib64 一些程序使用的动态函数库
/usr/share/doc 一些基本的软件使用手册与帮助文档
/usr/share/man 一些man page文件

[转载]ASP.NET MVC+JQueryEasyUI1.4+ADO.NET Demo - Dr_Hao - 博客园
来源: [转载]ASP.NET MVC+JQueryEasyUI1.4+ADO.NET Demo – Dr_Hao – 博客园
DrHao.CMS整体参考源代码:链接:http://pan.baidu.com/s/1jHfpkmM%20 密码:f2t8
MVCBlog(ASP.NET MVC 4.0+EF 简单Demo) 链接:http://pan.baidu.com/s/1bkVvcU 密码:1c2f
Q:我在DrHao.CMS中定义一个BaseController控制器,代码如下:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.Web.Mvc;
6 using System.Web.Providers.Entities;
7
8 namespace DrHao.CMS.WebApp.Controllers
9 {
10 public class BaseController : Controller
11 {
12 //
13 // GET: /Base/
14 protected override void OnActionExecuting(ActionExecutingContext filterContext)
15 {
16 if (Session["UserInfo"]==null)
17 {
18 //没效果,还是会执行Action的方法
19 filterContext.HttpContext.Response.Redirect("/Login/Index");
20 }
21 base.OnActionExecuting(filterContext);
22 }
23
24 }
25 }
运行DrHao.CMS 直接访问 /Home/Index ,HomeController继承BaseController 代码如下:
1 using DrHao.CMS.Model;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Web;
6 using System.Web.Mvc;
7
8 namespace DrHao.CMS.WebApp.Controllers
9 {
10 public class HomeController : BaseController
11 {
12 //
13 // GET: /Home/
14
15 public ActionResult Index()
16 {
17 UserInfo user = Session["UserInfo"] as UserInfo;
18 //user判断 正常情况下不需要写
19 if (user == null)
20 {
21 return Redirect("/Login/Index");
22 }
23 else
24 {
25 ViewBag.userLogin = user.UUserName;
26 return View();
27 }
28
29 }
30
31 }
32 }
正常情况下,在没有登陆当前用户的时候,直接访问/Home/Index,会执行BaseController中的 protected override void OnActionExecuting(ActionExecutingContext filterContext)方法,判断当前用户没有登陆,则直接跳转,不会执行/Home/Index Action中的方法,但实际运行效果,会继续执行/Home/Index中的方法(若在/Home/Index中不加入判断,则直接抛出异常信息,user不能为null)
1:直接访问/Home/Index View,执行代码如下:

2:判断当前Session[“UserInfo”]==null,执行跳转代码,但是还会继续执行base.OnActionExecuting(filterContext);方法

3:执行完BaseController中OnActionExecuting方法,则会继续执行HomeController控制器下的Index Action(按照我的理解不应该继续执行)


关于这点疑问,各位博友,有什么好的办法或者见解,帮我解惑一下,谢谢!
dede织梦data目录正确迁移及引起的问题解决方法
关于将dede织梦data目录迁移出web目录织梦官方提供了一个教程,但是如果 你是按照他们提供的教程做的话会出现很多问题。比如验证码问题,图片显示问题等等一大堆。织梦官方这种是很不负责任的,因为那个教程有很大缺陷。这里跟大 家提供一个完整版本的如何将dede织梦data目录正确迁移,以及按照官方版本教程迁移出现问题的解决办法。这里先看看官方的吧,然后我再补充。
1、将data目录转移到非Web目录
我们这里举例“D:\dedecms\v57”为我们系统的根目录,我们需要将目录下的data文件夹(如图1)迁移要上一级目录(非Web目录),简单的办法直接剪切或者拷贝即可。


找到系统目录下/include/common.inc.php文件,修改DEDEDATA常量为你的系统目录。

进入系统后台,在配置中修改tplcache目录为你想对目录。

转移data目录后验证码不显示或者输入验证码一直提示错误
不显示验证码的同学请改一下/include/vdimgck.php这个文件 这个文件里也调用了DATA里的文件也可以改路径,把带有这个 /../data 改成你现在的路径。
$im = @imagecreatefromjpeg(dirname(__FILE__).'/data/vdcode.jpg');
首页index.php文件也需要修改
还需要把首页中index.php中的/data/改为/../data。也就是下面这句。
if(!file_exists(dirname(__FILE__).'/data/common.inc.php'))
{
header('Location:install/index.php');
exit();
}
DEDECMS默认生成的rss地图以及网站地图等都是生成在DATA的文件夹中,但是这个是一个非常重要的文件夹,一般我们在 Robots.txt 是禁止搜索引擎爬行这文件夹的,这就造成了,我们生成了地图,但是搜索根本就找不到的尴尬,下面就教大家如何更改自动生成的目录
下面是详细的步骤:
1,首先登录ftp,在根目录下建立rss文件夹
2,修改根目录下你的管理员文件夹(默认是dede)下的makehtml_map.php文件
将17行的$cfg_cmspath."/data/sitemap.html";改为 $cfg_cmspath."/sitemap.html"; 将22行的$cfg_cmspath."/data/rssmap.html";改为 $cfg_cmspath."/rssmap.html";
17行是普通网站地图,22行是RSS的网站地图
3,修改根目录下include下面的arc.rssview.class.php
将71行的$murl = $GLOBALS['cfg_cmspath']."/data/rss/".$this->TypeID.".xml";改为 $murl = $GLOBALS['cfg_cmspath']."/rss/".$this->TypeID.".xml";
4,修改根目录下include下的sitemap.class.php
将57行的$typelink = $GLOBALS['cfg_cmsurl']."/data/rss/".$row->id.".xml"; $typelink = $GLOBALS['cfg_cmsurl']."/rss/".$row->id.".xml"; 将94行的$typelink = $GLOBALS['cfg_cmsurl']."/data/rss/".$row->id.".xml"; $typelink = $GLOBALS['cfg_cmsurl']."/rss/".$row->id.".xml";
5,修改/templets/default模板文件head.htm
在11行左右找到
<li class="r3"><a href="{dede:global.cfg_dataurl/}/sitemap.html">网站地图</a></li>
<li class="r4"><a href="{dede:global.cfg_dataurl/}/rssmap.html">RSS订阅</a></li>
改为
<li class="r3"><a href="{dede:global.cfg_cmsurl/}/sitemap.html">网站地图</a></li>
<li class="r4"><a href="{dede:global.cfg_cmsurl/}/rssmap.html">RSS订阅</a></li>
6,进入后台,更新网站地图,更新RSS文件,更新主页。
[转载]2014年国人开发的最热门的.NET开源项目 TOP 25 - dapeng888 - 博客园
来源: [转载]2014年国人开发的最热门的.NET开源项目 TOP 25 – dapeng888 – 博客园
原文地址:http://www.cnphp6.com/archives/72213
1 奎宇工作室 / DotNetCodes C#
一些常用的功能性代码,可以减少许多开发时间,而且类与类之间没有什么依赖,每个类都可以单独拿出来使用
2 beyonehu / manual_dota C#
《刀塔传奇》开源项目,服务器+客户端,蛮牛主办深圳玩贝科技组织http://www.unitymanual.com/forum-p…
3 oschina / wp7-app C#
OSCHINA 的 Windows Phone 7 客户端源码,可直接在 Marketplace 上搜索“开源中国”来安装此app
4 anycmd / anycmd C#
一个.net平台的完全开源的,完整支持rbac的,将会支持xacml、JavaScript的通用的权限框架、引擎、中间件、解决方案。
5 kerryjiang / SuperSocket C#
SuperSocket 是一个轻量级的可扩展的 Socket 开发框架,可用来构建一个服务器端 Socket 程序,而无需了解如何使用…
6 Scut / Scut C#
Scut游戏服务器引擎是使用C#语言开发,特别适用于手机网络游戏,支持使用Python脚本进行游戏开发;可以支持多种数据库:支持HTT…
7 nbboy / CommOAuth2 C#
支持国内淘宝,支付宝,新浪,微信,腾讯微博快捷登录
8 wojilu / wojilu C#
(1)一个 .net 平台下的全栈式、轻量级开发框架,包括 ORM、MVC、IOC、AOP、JSON、LOG 等,同时包括全套图文教程…
9 海洋饼干 / AForge.NET C#
AForge.NET 是一个专门为开发者和研究者基于C#框架设计的,他包括计算机视觉与人工智能,图像处理,神经网络,遗传算法,机器学习…
10 奎宇工作室 / Asp.Net Mvc WebManger C#
11 bobo2cj / iamge2text C#
识别出图片里的数字和字母
12 gsbhzh / GG C#
可在广域网部署运行的QQ高仿版 — GG叽叽。 项目地址:http://www.cnblogs.com/justnow/
13 cheng5x / Yc.QrCode C#
码晒客/疯狂创意二维码,底层 ,模版制作开源
14 longshine / Mina.NET C#
Mina.NET是.NET上的轻量级高性能网络程序框架,支持TCP、UDP和串口等多种传输通道,能够帮助开发者快速地开发高伸缩性的应用程序。
15 葡萄城控件 / ActiveReports C#
ActiveReports是一款在全球范围内应用非常广泛的报表控件,以提供.NET报表所需的全部报表设计功能领先于同类报表控件,包括对…
16 wangwei123 / easy4net C#
easy4net是一个轻量级orm框架,灵活在于可以自己编写复杂的SQL语句查询,简单在于几分钟内便能上手使用,并支持mySQL, m…
17 wobumang / wbm.weixinmpsdk C#
微信公众平台SDK。一个更方便,更快速的C#SDK,希望能帮助更多的朋友学习和使用
18 rainy_blue_sky / SmartHomeChat C#
用于局域网的聊天软件, 从其他开源平台上移植过来的, 感觉不错! 开发平台: VS2012 开发语言: …
19 bobo2cj / SimpleWinformFrame C#
简单的winform开发架子,客户端主程序(tabControl),客户端自动更新程序(WebClient),服务端更新列表生成器(XML)
20 _Jerry / JLib C#
C#类库
21 kerryjiang / SuperWebSocket C#
SuperWebSocket是WebSocket协议服务器端的.NET实现. 作为HTML5的一个重要新特性,WebSocket 规…
22 yqblog / yqblog C#
yqblog-基于MVC,Bootstrap的个人博客系统
23 Aimeast / GitCandy C#
GitCandy是一个开源的基于ASP.NET Mvc的轻量级Git服务端。 QQ交流群:200319579
24 xiaocong_soft / CheckUpdate.Net C#
Winform开发的检查更新程序。可用于Winform/WPF,主要功能包括更新文件、更新程序自身、下载安装包等。
25 奎宇工作室 / NoIIS C#
基于.net4.0的免装IIS运行程序的工具,只要安装.net4.0,就可以快速启动网站程序,为客户演示提供方便
Mikel




