cURL 是一个利用URL语法规定来传输文件和数据的工具,支持很多协议和选项,如HTTP、FTP、TELNET等,能提供 URL 请求相关的各种细节信息。最爽的是,PHP 也支持 cURL 库。
本文将介绍 cURL 的一些高级特性,以及在 PHP 中如何运用它。
是的,我们可以通过其他办法获取网页内容。大多数时候,我因为想偷懒,都直接用简单的 PHP 的 file_get_contents() 函数:
$content = file_get_contents("http://www.awaimai.com");
$lines = file("http://www.awaimai.com");
readfile(http://www.awaimai.com);
不过,这种做法缺乏灵活性和有效的错误处理。而且,你也不能用它完成一些高难度任务,比如处理:coockies、验证、表单提交、文件上传等等。
首先,我们得先要确定 PHP 是否开启了这个库,你可以通过使用phpinfo()
函数来得到这一信息。如果在网页上看到下面的输出,那么表示 cURL 库已开启。
如果 curl 没有开启,那么就需要开启这个库。如果是在Windows平台下,那么非常简单,你需要改一改 php.ini
文件的设置,找到 php_curl.dll
,并取消前面的分号注释就行了。如下所示:
# 取消下面的注释
extension=php_curl.dll
如果是 Linux 服务器,需要重新编译 PHP ,编译时在configure
命令上加上--with-curl
参数。
在学习更为复杂的功能之前,先来看一下在 PHP 中建立 cURL 请求的基本步骤:
实现代码如下:
// 1. 初始化
$ch = curl_init();
// 2. 设置选项
curl_setopt($ch, CURLOPT_URL, "http://www.awaimai.com"); // 设置要抓取的页面地址
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 抓取结果直接返回(如果为0,则直接输出内容到页面)
curl_setopt($ch, CURLOPT_HEADER, 0); // 不需要页面的HTTP头
// 3. 执行并获取HTML文档内容,可用echo输出内容
$output = curl_exec($ch);
// 4. 释放curl句柄
curl_close($ch);
第二步(也就是 curl_setopt()
)最为重要,一切玄妙均在此。有一长串cURL参数可供设置,它们能指定 URL 请求的各个细节。要一次性全部看完并理解可能比较困难,所以今天我们只试一下那些更常用也更有用的选项。
你可以在 cur_exec()
后加一段检查错误的语句(虽然这并不是必需的):
$output = curl_exec($ch);
if ($output === FALSE) {
echo "cURL Error: " . curl_error($ch);
}
请注意,比较的时候我们用的是=== FALSE
,而非== FALSE
。因为我们得区分空输出
和布尔值FALSE
,后者才是真正的错误。
利用curl_getinfo()
能够在 cURL 执行后获取请求的有关信息,当然,这也是一个可选的设置项,:
curl_exec($ch);
$info = curl_getinfo($ch);
echo '获取'. $info['url'] . '耗时'. $info['total_time'] . '秒';
返回的数组中包括了以下信息:
在第一个例子中,我们将提供一段用于侦测服务器是否有基于浏览器的重定向的代码。例如,有些网站会根据是否是手机浏览器甚至用户来自哪个国家来重定向网页。
我们利用 CURLOPT_HTTPHEADER
选项来设定发送出的HTTP请求头信息(http headers),包括user agent信息和默认语言。然后看看这些特定网站是否会把我们重定向到不同的URL。
// 测试用的URL
$urls = array(
"http://www.bbc.com",
"http://www.baidu.com",
"http://www.ubuntu.com"
);
// 测试用的浏览器信息
$browsers = array(
"standard" => array (
"user_agent" => "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729)",
"language" => "en-us,en;q=0.5"
),
"iphone" => array (
"user_agent" => "Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A537a Safari/419.3",
"language" => "en"
),
"french" => array (
"user_agent" => "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB6; .NET CLR 2.0.50727)",
"language" => "fr,fr-FR;q=0.5"
)
);
foreach ($urls as $url) {
echo "URL: $url\n<br />";
foreach ($browsers as $test_name => $browser) {
$ch = curl_init();
// 设置 url
curl_setopt($ch, CURLOPT_URL, $url);
// 设置浏览器的特定header
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"User-Agent: {$browser['user_agent']}",
"Accept-Language: {$browser['language']}"
));
// 页面内容我们并不需要
curl_setopt($ch, CURLOPT_NOBODY, 1);
// 只需返回HTTP header
curl_setopt($ch, CURLOPT_HEADER, 1);
// 返回结果,而不是输出它
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
// 有重定向的HTTP头信息吗?
if (preg_match("!Location: (.*)!", $output, $matches)) {
echo "$test_name: redirects to $matches[1]\n<br />";
} else {
echo "$test_name: no redirection\n<br />";
}
}
echo "\n\n<br /><br />";
}
首先,我们建立一组需要测试的URL,接着指定一组需要测试的浏览器信息。最后通过循环测试各种URL和浏览器匹配可能产生的情况。
因为我们指定了CURLOPT_NOBODY
选项,所以返回的输出内容则只包括HTTP头信息(被存放于 $output
中)。利用一个简单的正则,我们检查这个头信息中是否包含了Location:
字样。
运行这段代码应该会返回如下结果:
URL: http://www.bbc.com
standard: no redirection
iphone: no redirection
french: no redirection
URL: http://www.baidu.com
standard: redirects to https://www.baidu.com/
iphone: no redirection
french: redirects to https://www.baidu.com/
URL: http://www.ubuntu.com
standard: redirects to http://www.ubuntu.com/index_kylin
iphone: redirects to http://www.ubuntu.com/index_kylin
french: redirects to http://www.ubuntu.com/index_kylin
当发起 GET 请求时,数据可以通过“查询字串”(Query String)传递给一个URL。例如,在必应(鉴于 Google 需要翻墙,用 Bing 代替)中搜索时,搜索关键即为 URL 的查询字串的一部分:
http://www.bing.com?q=awaimai.com
这种情况下你可能并不需要 cURL 来模拟。把这个URL丢给 file_get_contents() 就能得到相同结果。
不过有一些HTML表单是用 POST 方法提交的。这种表单提交时,数据是通过 HTTP请求体(request body) 发送,而不是查询字串。例如,当使用ThinkPHP网站的搜索功能时,无论输入什么关键字,总是被 POST 到如下页面:
http://www.thinkphp.cn/Search/
你可以用 PHP 脚本来模拟这种 URL 请求。首先,新建一个可以接受并显示 POST 数据的文件,我们给它命名为 post_output.php,脚本内容为:
print_r($_POST);
接下来,写一段 PHP 脚本来执行 cURL 请求:
$url = "http://localhost/post_output.php";
$post_data = array (
"foo" => "bar",
"query" => "Nettuts",
"action" => "Submit"
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// 我们在POST数据哦!
curl_setopt($ch, CURLOPT_POST, 1);
// 加上POST变量
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$output = curl_exec($ch);
curl_close($ch);
echo $output;
执行代码后应该会得到以下结果:
Array
(
[foo] => bar
[query] => Nettuts
[action] => Submit
)
这段脚本发送一个 POST 请求给 post_output.php ,这个页面 $_POST
变量并返回,我们利用 cURL 捕捉了这个输出。
上传文件和前面的 POST 十分相似。因为所有的文件上传表单都是通过POST方法提交的。首先新建一个接收文件的页面,命名为 upload_output.php,页面内容:
print_r($_FILES);
以下是真正执行文件上传任务的脚本,命名为 upload.php,内容:
$url = "http://localhost/upload_output.php";
$post_data = array (
"foo" => "bar",
// 要上传的本地文件地址
"upload" => "@C:/wamp/www/test.zip"
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$output = curl_exec($ch);
curl_close($ch);
echo $output;
如果你需要上传一个文件,只需要把文件路径赋给upload
,作为 POST
变量传过去,不过记得在前面加上符号。执行这段脚本应该会得到类似如下输出:
Array
(
[upload] => Array
(
[name] => test.zip
[type] => application/octet-stream
[tmp_name] => C:\Windows\php1BB4.tmp
[error] => 0
[size] => 487235
)
)
cURL还有一个高级特性:批处理句柄(handle)。这一特性允许你同时或异步地打开多个URL连接。下面是来自来自php.net的示例代码:
// 创建两个cURL资源
$ch1 = curl_init();
$ch2 = curl_init();
// 指定URL和适当的参数
curl_setopt($ch1, CURLOPT_URL, "http://lxr.php.net/");
curl_setopt($ch1, CURLOPT_HEADER, 0);
curl_setopt($ch2, CURLOPT_URL, "http://www.php.net/");
curl_setopt($ch2, CURLOPT_HEADER, 0);
// 创建cURL批处理句柄
$mh = curl_multi_init();
// 加上前面两个资源句柄
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
// 预定义一个状态变量
$active = null;
// 执行批处理
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
while ($active && $mrc == CURLM_OK) {
if (curl_multi_select($mh) != -1) {
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}
// 关闭各个句柄
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);
这里要做的就是打开多个 cURL 句柄并指派给一个批处理句柄。然后你就只需在一个while
循环里等它执行完毕。
这个示例中有两个主要循环。第一个 do-while
循环重复调用 curl_multi_exec()
。这个函数是无隔断(non-blocking)的,但会尽可能少地执行。它返回一个状态值,只要这个值等于常量 CURLM_CALL_MULTI_PERFORM
,就代表还有一些刻不容缓的工作要做(例如,把对应URL的http头信息发送出去)。也就是说,我们需要不断调用该函数,直到返回值发生改变。
而接下来的 while
循环,只在 $active
变量为 true
时继续。这一变量之前作为第二个参数传给了 curl_multi_exec()
,代表只要批处理句柄中是否还有活动连接。接着,我们调用 curl_multi_select()
,在活动连接(例如接受服务器响应)出现之前,它都是被“屏蔽”的。这个函数成功执行后,我们又会进入另一个 do-while
循环,继续下一条URL。
还是来看一看怎么把这一功能用到实处吧:
想象一下你有一个文章数目庞大的博客,这些文章中包含了大量外部网站链接。一段时间之后,因为这样那样的原因,这些链接中相当数量都失效了。要么是被和谐了,要么是整个站点都被功夫网了…
我们下面建立一个脚本,分析所有这些链接,找出打不开或者404的网站/网页,并生成一个报告。
请注意,以下并不是一个真正可用的WordPress插件,仅仅是一段独立功能的脚本而已,仅供演示,谢谢。
好,开始吧。首先,从数据库中读取所有这些链接:
// 配置 MySQL 数据库
$db_host = 'localhost';
$db_user = 'root';
$db_pass = '';
$db_name = 'wordpress';
$excluded_domains = array('localhost', 'www.mydomain.com');
$max_connections = 10;
// 初始化一些变量
$url_list = array();
$working_urls = array();
$dead_urls = array();
$not_found_urls = array();
$active = null;
// 连到 MySQL
if (!mysql_connect($db_host, $db_user, $db_pass)) {
die('Could not connect: ' . mysql_error());
}
if (!mysql_select_db($db_name)) {
die('Could not select db: ' . mysql_error());
}
// 找出所有含有链接的文章
$sql = "SELECT post_content FROM wp_posts
WHERE post_content LIKE '%href=%'
AND post_status = 'publish'
AND post_type = 'post'";
$res = mysql_query($sql) or die(mysql_error());
while ($d = mysql_fetch_assoc($res)) {
// 用正则匹配链接
if (preg_match_all("!href=\"(.*?)\"!", $d['post_content'], $matches)) {
foreach ($matches[1] as $url) {
// 剔除排除的域名
$tmp = parse_url($url);
if (in_array($tmp['host'], $excluded_domains)) {
continue;
}
// 保存 URL
$url_list []= $url;
}
}
}
// 移除重复链接
$url_list = array_values(array_unique($url_list));
if (!$url_list) {
die('No URL to check');
}
我们首先配置好数据库,一系列要排除的域名($excluded_domains
),以及最大同时连接数量($max_connections
)。然后,连接数据库,获取文章和包含的链接,把它们收集到一个数组中($url_list
)。
下面的代码有点复杂了,因此我将一小步一小步地详细解释:
// 1. 批处理器
$mh = curl_multi_init();
// 2. 加入需批量处理的URL
for ($i = 0; $i < $max_connections; $i++) {
add_url_to_multi_handle($mh, $url_list);
}
// 3. 初始处理
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
// 4. 主循环
while ($active && $mrc == CURLM_OK) {
// 5. 有活动连接
if (curl_multi_select($mh) != -1) {
// 6. 干活
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
// 7. 有信息否?
if ($mhinfo = curl_multi_info_read($mh)) {
// 意味着该连接正常结束
// 8. 从curl句柄获取信息
$chinfo = curl_getinfo($mhinfo['handle']);
// 9. 死链么?
if (!$chinfo['http_code']) {
$dead_urls []= $chinfo['url'];
// 10. 404了?
} else if ($chinfo['http_code'] == 404) {
$not_found_urls []= $chinfo['url'];
// 11. 还能用
} else {
$working_urls []= $chinfo['url'];
}
// 12. 移除句柄
curl_multi_remove_handle($mh, $mhinfo['handle']);
curl_close($mhinfo['handle']);
// 13. 加入新URL,干活
if (add_url_to_multi_handle($mh, $url_list)) {
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}
}
}
// 14. 完了
curl_multi_close($mh);
echo "==Dead URLs==\n";
echo implode("\n",$dead_urls) . "\n\n";
echo "==404 URLs==\n";
echo implode("\n",$not_found_urls) . "\n\n";
echo "==Working URLs==\n";
echo implode("\n",$working_urls);
// 15. 向批处理器添加url
function add_url_to_multi_handle($mh, $url_list) {
static $index = 0;
// 如果还剩url没用
if ($url_list[$index]) {
// 新建curl句柄
$ch = curl_init();
// 配置url
curl_setopt($ch, CURLOPT_URL, $url_list[$index]);
// 不想输出返回的内容
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// 重定向到哪儿我们就去哪儿
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
// 不需要内容体,能够节约带宽和时间
curl_setopt($ch, CURLOPT_NOBODY, 1);
// 加入到批处理器中
curl_multi_add_handle($mh, $ch);
// 拨一下计数器,下次调用该函数就能添加下一个url了
$index++;
return true;
} else {
// 没有新的URL需要处理了
return false;
}
}
下面解释一下以上代码。列表的序号对应着代码注释中的顺序数字。
add_url_to_multi_handle()
。每当这个函数被调用,就有一个新url被加入批处理器。一开始,我们给批处理器添加了10
个URL(这一数字由 $max_connections
所决定)。curl_multi_exec()
进行初始化工作是必须的,只要它返回 CURLM_CALL_MULTI_PERFORM
就还有事情要做。这么做主要是为了创建连接,它不会等待完整的URL响应。curl_multi_select()
会一直等待,直到某个URL查询产生活动连接。$index
就递增一次,这样我们才能知道还剩多少 URL 没处理。我把这个脚本在我的博客上跑了一遍(测试需要,有一些错误链接是故意加上的),共检查约40个URL,只耗费两秒不到。当需要检查更加大量的URL时,其省心省力的效果可想而知!如果你同时打开10个连接,还能再快上10倍!另外,你还可以利用cURL批处理的无隔断特性,来处理大量URL请求,而不会阻塞你的Web脚本。
如果某个URL请求需要基于 HTTP 的身份验证,你可以使用下面的代码:
$url = "http://www.somesite.com/members/";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// 发送用户名和密码
curl_setopt($ch, CURLOPT_USERPWD, "myusername:mypassword");
// 你可以允许其重定向
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
// 下面的选项让 cURL 在重定向后
// 也能发送用户名和密码
curl_setopt($ch, CURLOPT_UNRESTRICTED_AUTH, 1);
$output = curl_exec($ch);
curl_close($ch);
PHP 自带有 FTP 类库, 但你也能用 cURL:
// 打开一个文件指针
$file = fopen("/path/to/file", "r");
$size = filesize("/path/to/file");
// url里包含了大部分所需信息
$url = "ftp://username:[email protected]:21/path/to/new/file";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// 上传相关的选项
curl_setopt($ch, CURLOPT_UPLOAD, 1);
curl_setopt($ch, CURLOPT_INFILE, $file);
curl_setopt($ch, CURLOPT_INFILESIZE, $size);
// 是否开启ASCII模式 (上传文本文件时有用)
curl_setopt($ch, CURLOPT_FTPASCII, 1);
$output = curl_exec($ch);
curl_close($ch);
你可以用代理发起 cURL 请求:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://www.example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// 指定代理地址
curl_setopt($ch, CURLOPT_PROXY, '11.11.11.11:8080');
// 如果需要的话,提供用户名和密码
curl_setopt($ch, CURLOPT_PROXYUSERPWD, 'username:password');
$output = curl_exec($ch);
curl_close ($ch);
可以在一个URL请求过程中,让 cURL 调用某指定的回调函数。例如,在内容或者响应下载的过程中,立刻开始利用数据,而不用等到完全下载完。
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://net.tutsplus.com');
curl_setopt($ch, CURLOPT_WRITEFUNCTION, "progress_function");
curl_exec($ch);
curl_close ($ch);
function progress_function($ch, $str) {
echo $str;
return strlen($str);
}
这个回调函数必须返回字串的长度,不然此功能将无法正常使用。在URL响应接收的过程中,只要收到一个数据包,这个函数就会被调用。
参考资料:
文章浏览阅读3.2k次。本文研究全球与中国市场分布式光纤传感器的发展现状及未来发展趋势,分别从生产和消费的角度分析分布式光纤传感器的主要生产地区、主要消费地区以及主要的生产商。重点分析全球与中国市场的主要厂商产品特点、产品规格、不同规格产品的价格、产量、产值及全球和中国市场主要生产商的市场份额。主要生产商包括:FISO TechnologiesBrugg KabelSensor HighwayOmnisensAFL GlobalQinetiQ GroupLockheed MartinOSENSA Innovati_预计2026年中国分布式传感器市场规模有多大
文章浏览阅读1.1k次,点赞2次,收藏12次。常用组合逻辑电路结构——为IC设计的延时估计铺垫学习目的:估计模块间的delay,确保写的代码的timing 综合能给到多少HZ,以满足需求!_基4布斯算法代码
文章浏览阅读3.3k次,点赞3次,收藏5次。OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版
文章浏览阅读2.2k次。USACO自1992年举办,到目前为止已经举办了27届,目的是为了帮助美国信息学国家队选拔IOI的队员,目前逐渐发展为全球热门的线上赛事,成为美国大学申请条件下,含金量相当高的官方竞赛。USACO的比赛成绩可以助力计算机专业留学,越来越多的学生进入了康奈尔,麻省理工,普林斯顿,哈佛和耶鲁等大学,这些同学的共同点是他们都参加了美国计算机科学竞赛(USACO),并且取得过非常好的成绩。适合参赛人群USACO适合国内在读学生有意向申请美国大学的或者想锻炼自己编程能力的同学,高三学生也可以参加12月的第_usaco可以多次提交吗
文章浏览阅读394次。1.1 存储程序1.2 创建存储过程1.3 创建自定义函数1.3.1 示例1.4 自定义函数和存储过程的区别1.5 变量的使用1.6 定义条件和处理程序1.6.1 定义条件1.6.1.1 示例1.6.2 定义处理程序1.6.2.1 示例1.7 光标的使用1.7.1 声明光标1.7.2 打开光标1.7.3 使用光标1.7.4 关闭光标1.8 流程控制的使用1.8.1 IF语句1.8.2 CASE语句1.8.3 LOOP语句1.8.4 LEAVE语句1.8.5 ITERATE语句1.8.6 REPEAT语句。_mysql自定义函数和存储过程
文章浏览阅读188次。半导体二极管——集成电路最小组成单元。_本征半导体电流为0
文章浏览阅读2.8k次,点赞3次,收藏18次。游戏水面特效实现方式太多。咱们这边介绍的是一最简单的UV动画(无顶点位移),整个mesh由4个顶点构成。实现了水面效果(左图),不动代码稍微修改下参数和贴图可以实现岩浆效果(右图)。有要思路是1,uv按时间去做正弦波移动2,在1的基础上加个凹凸图混合uv3,在1、2的基础上加个水流方向4,加上对雾效的支持,如没必要请自行删除雾效代码(把包含fog的几行代码删除)S..._unity 岩浆shader
文章浏览阅读5k次。广义线性模型是线性模型的扩展,它通过连接函数建立响应变量的数学期望值与线性组合的预测变量之间的关系。广义线性模型拟合的形式为:其中g(μY)是条件均值的函数(称为连接函数)。另外,你可放松Y为正态分布的假设,改为Y 服从指数分布族中的一种分布即可。设定好连接函数和概率分布后,便可以通过最大似然估计的多次迭代推导出各参数值。在大部分情况下,线性模型就可以通过一系列连续型或类别型预测变量来预测正态分布的响应变量的工作。但是,有时候我们要进行非正态因变量的分析,例如:(1)类别型.._广义线性回归模型
文章浏览阅读69次。环境保护、 保护地球、 校园环保、垃圾分类、绿色家园、等网站的设计与制作。 总结了一些学生网页制作的经验:一般的网页需要融入以下知识点:div+css布局、浮动、定位、高级css、表格、表单及验证、js轮播图、音频 视频 Flash的应用、ul li、下拉导航栏、鼠标划过效果等知识点,网页的风格主题也很全面:如爱好、风景、校园、美食、动漫、游戏、咖啡、音乐、家乡、电影、名人、商城以及个人主页等主题,学生、新手可参考下方页面的布局和设计和HTML源码(有用点赞△) 一套A+的网_垃圾分类网页设计目标怎么写
文章浏览阅读614次,点赞7次,收藏11次。之前找到一个修改 exe 中 DLL地址 的方法, 不太好使,虽然能正确启动, 但无法改变 exe 的工作目录,这就影响了.Net 中很多获取 exe 执行目录来拼接的地址 ( 相对路径 ),比如 wwwroot 和 代码中相对目录还有一些复制到目录的普通文件 等等,它们的地址都会指向原来 exe 的目录, 而不是自定义的 “lib” 目录,根本原因就是没有修改 exe 的工作目录这次来搞一个启动程序,把 .net 的所有东西都放在一个文件夹,在文件夹同级的目录制作一个 exe._.net dll 全局目录
文章浏览阅读1.5k次。本文为转载,原博客地址:http://blog.csdn.net/hujingshuang/article/details/46910259简介 BRIEF是2010年的一篇名为《BRIEF:Binary Robust Independent Elementary Features》的文章中提出,BRIEF是对已检测到的特征点进行描述,它是一种二进制编码的描述子,摈弃了利用区域灰度..._breif description calculation 特征点
文章浏览阅读4.1k次,点赞21次,收藏79次。本文是《基于SpringBoot的房屋租赁管理系统》的配套原创说明文档,可以给应届毕业生提供格式撰写参考,也可以给开发类似系统的朋友们提供功能业务设计思路。_基于spring boot的房屋租赁系统论文