Windows环境下安装phpunit

参考文章:http://blog.csdn.net/sunshinelyc/article/details/49834293#comments

进来由于工作需要,安装phpunit,在网上找了各种安装方法,pear添加phpunit通道安装,手动安装,各种失效,各种无语,皆因网上的资料都是年份比较久远的(也有可能本人不太了解phpunit的工作原理),导致安装了一个下午进展缓慢。最后在phpunit.de中看到了一篇文章,然后第二天再试着安装了一次,具体成功了(然后也对phpunit有了一个比较基础的了解)故此,记录一下本人安装phpunit的过程,方便自己和路人查阅,该文章仅作为本人查阅之用,故此希望网友看到了不要吐槽。。微笑

话不多说,直接开展。。。

首先,官网文档连接如下phpunit.de ,如果是由于年份久远导致无法连接的只能再找找资料了(再网上找资料的时候就碰到了一大推年份久远导致链接失效的情况。。。大哭,导致坑越来越深。。。)

安装步骤如下:

其实安装过程非常非常非常简单。。(注意用了三个非常,足以证明强调意义)

1、在官网下载phpunit.phar包,链接如下:phpunit.phar,下载和自己php版本对应的稳定包即可。(注意:这里是PHPUnit 的 PHP 档案包,它将 PHPUnit 所需要的所有必要组件(以及某些可选组件)捆绑在这个文件中)

2、创建一个文件夹,这里我在d盘创建了phpunit,路径为D:\phpunit,将该路径添加到path环境变量中,然后将下载好的phpunit.phar放到该文件夹中

3、打开一个cmd窗口,按照如下执行(每个人的cmd路径不一样,不要对号入座。。):

C:\Users\Administrator>d:

D:\>cd phpunit

D:\phpunit>echo @php “%~dp0phpunit.phar” %* > phpunit.cmd

D:\phpunit>exit

4、重新打开一个新的cmd窗口,在cmd中执行执行phpunit –version

C:\Users\Administrator>phpunit –version
PHPUnit 4.8.18 by Sebastian Bergmann and contributors.

这样子就表示你的phpunit已经安装完成了。。是不是超级简单。。不到半个小时就搞定的事情,我昨天研究了一个下午。。也是够蠢的。。。(不要局限于用pear安装。安装方法各种各样。结果达到就行。。),暂时介绍安装。后续继续补充phpunit的学习过程,毕竟这东西,才有一点点概念。至于怎么使用。原理是什么还是一头雾水。。

Zend Framework单元测试方法

Update: Things are all change in Zend Framework 1.8, so this may require some adaptation in that version.

If you’ve followed the Zend Framework quickstart tutorial like me, you may be wondering how to perform unit testing using it. The tutorial does set up the bootstrap file to allow for unit testing, but does not cover unit testing itself. The aim of this post is to  provide a quick guide to unit testing using the quickstart application, which will hopefully come in useful for a few people and myself when I inevitably forget this later on.

Step 0: Before Starting

First, you should download and set up the guestbook application from the Zend Framework website. Make sure you place the Zend library in the library folder and enable the read/write permissions for the sqlite database and the db directory for access by the web server.

You will also want to install pear and, with it, install PHPUnit:

pear channel-discover pear.phpunit.de

pear install phpunit/PHPUnit

Step 1: Create Test Folders

Create a folder called “tests” in the root folder of the application. Inside that create a folder called “controllers” and “models”. The  directory structure should be as follows:

zendquickstart
|-- application
|-- data
|-- library
|-- public
|-- scripts
`--tests
 |-- controllers
 `-- models

All your controller tests should go in the controllers folder, all your model tests should go in the models folder.

Step 2: Create Test Configuration

Create the file TestConfiguration.php in the tests folder. This file will initially set up the testing configuration, inside place the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
// Gets called when this file is included/required
TestConfiguration::setUp();

class TestConfiguration
{
    /**
    * Sets the environment up for testing
    */
    static function setUp()
    {
        // Set the environment constant to testing which will load the testing
        // configuration in app.ini by the bootstrap
        define('APPLICATION_ENVIRONMENT', 'testing');

        // Set the include path for locating the Zend library
        set_include_path(realpath(dirname(__FILE__)) . '/../library'
            . PATH_SEPARATOR . get_include_path());

        // Use Autoload so that we don't have to include/require every class
        require_once "Zend/Loader.php";
        Zend_Loader::registerAutoload();
    }

    static function setUpDatabase()
    {
        require '../application/bootstrap.php';

        $db = Zend_Registry::get('configuration')->database->params->dbname;

        // delete any pre-existing databases
        if(file_exists($db)) unlink($db);

        // run the database set up script to recreate the database
        require '../scripts/load.sqlite.php';
    }
}
?>

The setUp() function in this class will get called when the file is included or required. The APPLICATION_ENVIRONMENT constant is set to ‘testing’ so that the testing section of the app.ini file is read in the bootstrap, and the testing database is used. A testing database should be used so that testing does not interfere with the production or development databases, and no important  data is lost. The next step is to set the include path, which should contain the location of the Zend Framework library. The final step is to enable the Zend autoloader so that we don’t have to explicitly require/include the Zend libraries.

The setUpDatabase() function resets the database to a known state. When the tests are run we may wish to insert data to the database and this should be removed before every new test. We require the bootstrap file so we can get the database configuration and delete the database file, which is an easy way to reset an SQLite database. A different method will be necessary for other databases like MySQL or PostgreSQL. Finally, the setUpDatabase() function uses a script which comes with the quick start application to (re)create the database.

Step 3: Creating Controller Tests

To test the IndexController, create the file IndexControllerTest.php in the tests/controller directory. The following is a simple example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
// Set up the testing environment
require 'TestConfiguration.php';

class controllers_IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
    // Bootstraps the application
    public $bootstrap = '../application/bootstrap.php';

    public function testHomePageIsASuccessfulRequest()
    {
        // Runs the test on /, the homepage
        $this->dispatch('/');

        // Tests there are no exceptions on the home page
        $this->assertFalse($this->response->isException());

        // Tests for redirection to the error handler
        $this->assertNotRedirect();
    }

    public function testHomePageDisplaysCorrectContent()
    {
        // Runs the test on /
        $this->dispatch('/');

        // Tests the page title is present
        $this->assertQueryContentContains(
            'div#header-logo',
            'ZF Quickstart Application'
        );

        // Tests the guestbook link is present
        $this->assertQueryContentContains('a', 'Guestbook');
    }
}
?>

This is a very basic controller test. First note that you should extend Zend_Test_PHPUnit_ControllerTestCase for controller tests. This class extends PHPUnit_Framework_TestCase itself, but adds some assertions and other things specific to Zend Framework.

The bootstrap instance variable must be set in order to test the controller, and in this case it points to the location of the bootstrap file.

The testHomePageIsASuccessfulRequest() test is used to test that the homepage functions correctly; it should not contain any exceptions or redirect to the error controller. If it does then there is a problem somewhere and the test fails. The testHomePageDisplaysCorrectContent() is used to test that the page title and the link to the guestbook is present.

Step 4: Creating Model Tests

To test the GuestBook model, create the file GuestBookTest.php in tests/models.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
require 'TestConfiguration.php';
require '../application/models/GuestBook.php';

class models_GuestBookTest extends PHPUnit_Framework_TestCase
{
    public function setUp()
    {
        // Reset database state
        TestConfiguration::setUpDatabase();
    }

    public function testFetchEntries()
    {
        // Instantiate the GuestBook model
        $guestBook = new Model_GuestBook();

        // Get all entries from the database
        $entries = $guestBook->fetchEntries();

        // Test that there are 2 entries in the guestbook
        $this->assertSame(2, count($entries));
    }
}
?>

Again, this is very basic. The setUp() function gets called by PHPUnit before the test is run, and it will reset the database. The testFetchEntries() function tests the fetchEntries() function in the model. Two rows in the guestbook table should be present, therefore there should be two elements in the array returned by fetchEntries().

Step 5: Edit load.sqlite.php

You may find it annoying to have to wait 5 seconds between model tests when the database is recreated. I worked around this problem by making a small change to the PHP script which loads the database schema:

1
2
3
4
5
6
7
8
9
<?php
if (APPLICATION_ENVIRONMENT != 'testing')
{
    echo 'Writing Database Guestbook in (control-c to cancel): ' . PHP_EOL;
    for ($x = 5; $x > 0; $x--) {
        echo $x . "\r"; sleep(1);
    }
}
?>

If the application environment is not testing then the timeout should not be displayed. You may prefer to simply remove the timeout altogether. Additionally, you will need to change the lines that locate the SQL files to include dirname(FILE):

1
2
3
4
<?php
$schemaSql = file_get_contents(dirname(__FILE__) . '/schema.sqlite.sql');
$dataSql = file_get_contents(dirname(__FILE__) . '/data.sqlite.sql');
?>

Step 6: Running the Tests

To run the tests, navigate to the tests directory in a terminal/CMD, and type phpunit controllers_IndexControllerTest and models_GuestBookTest to test the IndexController and GuestBook model, respectively.

phpunit controllers_IndexControllerTest

PHPUnit 3.3.14 by Sebastian Bergmann.

..

Time: 0 seconds

OK (2 tests, 4 assertions)

phpunit models_GuestBookTest

PHPUnit 3.3.14 by Sebastian Bergmann.

Database Created

Data Loaded.

.

Time: 0 seconds

OK (1 test, 1 assertion)

Conclusion

There you have it. This isn’t necessarily the only way or the best way to perform unit testing, this is merely the way I got it to work with the quickstart application having had no prior experience with PHPUnit. Any suggestions or improvements are welcome.

Credits

I based this on the Zend Framework manual and the book Zend Framework in Action.

Unity导出Android工程Gradle时填坑

Player Settings中选择Use Existing Keystore文件后,可以输入Keystore password,但是Confirm keystore password却无法输入。

这个时候点击Key下面的Alias下拉框,提示Choose Android SDK root folder,按说我的Android SDK目录是/Users/xxxx/Library/sdk,但诡异的一点就是无法找到该目录,但是终端中是可以找到的。

后来百度了一下,在选择目录时按下快捷键shift+command+g,然后输入“/Users/xxxx/Library/”就可以找到该目录了。然后Key下面的Alias下拉框终于可以下拉了。

Xcode 占用空间太大的清理办法,超实用!

写在前面

最近突然发现我的128G SSD硬盘只剩下可怜的8G多,剩下这么少的一点空间连Xcode都无法更新。怎么办呢?如果升级硬盘的话,第一要花钱,毕竟SSD硬盘还是不便宜,第二是升级比较麻烦,要拆机和迁移系统什么的特别花时间精力,老了真不愿瞎折腾了,只能想办法能不能清除点空间来。

寻找大块头

首先想到的就是能不能删掉安装在SSD硬盘里面平时不用或者很少用到软件,可是仔细一看发现每个软件都是精心挑选,辛辛苦苦安装上去的,看来看去都不舍得卸载掉;好吧,那就看看能不能清掉下载文件夹里面某些没用的文件,最后删来删去也就删了几百兆,后来才想起来好像之前硬盘空间紧张已经清理过一次了…

继续在硬盘里寻找可以清除的文件,不久大发现来了,用户文件夹下的 资源库 这个文件夹特别大,进到这个文件夹发现大块头是 Developer 文件夹,原来是Xcode耗费了我那么多空间!

开始清理

下面这几个是我主要清理的文件夹:

  1. 这里放的是连接真机生成的文件,可以全部删掉或者把不常用的版本删掉,再次连接设备会自动生成
       > ~/Library/Developer/Xcode/iOS DeviceSupport
  2. app打包生成的文件,可以删掉不需要的项目打包文件
       > ~/Library/Developer/Xcode/Archives
  3. 项目的索引文件等,可以全部删除,或者删除不常用的项目,再次打开项目会自动生成
       > ~/Library/Developer/Xcode/DerivedData

经过清理,硬盘可用空间一下子变成了28G多,整整多了20多G!

最后

如果你也和我一样空间不够又不想升级硬盘,赶紧看看你的 ~/Library/Developer/Xcode/ 文件夹,如无意外应该也有惊喜。

The End.

作者:Mellong
链接:http://www.jianshu.com/p/03fed9a5fc63
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Visual Studio内置IIS服务器如何允许局域网内其它电脑远程访问?

参考文章:http://blog.csdn.net/zhangjk1993/article/details/36671105

用Visual Studio启动网站后,仅支持本地调试访问,其它电脑访问会报Invalid Hostname 400等错误。如何解决呢?

  1. 在VS中启动网站后,屏幕右下角会出现IIS Express的托盘图标。
  2. 点击托盘,选择查看所有,点击列表中的该网站,即可看到下方提示中包含一项applicationhost.config及该文件的位置。
  3. 找到该文件进行编辑, 找到<binding protocol=“http” bindingInformation=“*:8080:localhost” />,将localhost改为本机的IP即可,比如192.168.1.110,或者改为*。
  4. 在VS中重新启动网站。

模块加载失败 请确保该二进制文件在指定的路径中 找不到指定的模块

原文地址:http://blog.csdn.net/u011677067/article/details/52431043

编写了一个桌面右键菜单的的Shell扩展,为了验证是否与其它系统是否兼容,故用虚拟机分别安装了Win7的64位和32位,XP的32位系统,结果注册时出现了以下问题。

反复检查,路径肯定是对的,dll模块在开发机上也没有问题,权限也使用了管理员权限。最后没有办法,就在虚拟机上安装了VS并编译程序,结果这下又能注册成功了。

锁定问题为环境配置,将项目配置属性—>常规—>MFC的使用 修改为在静态库中使用MFC。

修改后,编译过,在注册运行就没有问题了。

其实最开始也考虑过可能是项目依赖的问题,但是因为创建的是ATL项目,只是将ATL的使用改为静态。

然而测试证明MFC的使用也要改为静态,这就有点不理解,哪位高手懂的请指教一下?

权限问题:

在XP中无需关心权限,直接用regsvr32命令来注册就行了。

在Win7中如果权限不足就会报错。

这个时候需要以管理员模式来执行。

另外,根据测试发现在Win7中权限问题要看用户配置:

如上图,如果将用户账户控制改为从不通知,那么即使一般权限也可以运行成功;但如果改为其它模式,那就必须以管理员权限来运行命令了。

微信公众号开发实现点击返回按钮就返回到聊天界面

原文地址:http://www.cnblogs.com/m-liuy/p/WeiXinBack.html

以下两段代码,取其中一段即可。

第一种:

pushHistory();

function pushHistory() {
var state = {
title: “title”,
url: “#”
};
window.history.pushState(state, “title”, “#”);
}

if (typeof window.addEventListener != “undefined”) {
window.addEventListener(“popstate”, function (e) {
WeixinJSBridge.call(‘closeWindow’);
}, false);
} else {
window.attachEvent(“popstate”, function (e) {
WeixinJSBridge.call(‘closeWindow’);
});
}

 

第二种

pushHistory();

function pushHistory() {
var state = {
title: “title”,
url: “#”
};
window.history.pushState(state, “title”, “#”);
}

$(function() {
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: ‘@ViewBag.AppID’, // 必填,公众号的唯一标识
timestamp: ‘@ViewBag.TimeStamp’, // 必填,生成签名的时间戳
nonceStr: ‘@ViewBag.NonceStr’, // 必填,生成签名的随机串
signature: ‘@ViewBag.Signature’, // 必填,签名,见附录1
jsApiList: [
‘checkJsApi’,
‘hideOptionMenu’,
‘scanQRCode’,
‘closeWindow’
] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});

wx.ready(function() {
wx.hideOptionMenu();
});

if (typeof window.addEventListener != “undefined”) {
window.addEventListener(“popstate”, function(e) {
wx.closeWindow();
}, false);
} else {
window.attachEvent(“popstate”, function(e) {
wx.closeWindow();
});
}
});

 

React Native 0.32以下版本Xcode8报错解决办法

原文地址:http://reactnative.cn/post/2595

RCTSRWebSocket.m报错

Ignoring return value of function declared with warn_unused_result attribute

这个报错在此文件中有两处,代码

SecRandomCopyBytes(kSecRandomDefault, sizeof(uint32_t), (uint8_t *)mask_key);

修改为

(void)SecRandomCopyBytes(kSecRandomDefault, sizeof(uint32_t), (uint8_t *)mask_key);

前面加上(void)

RCTScrollView.m 报错

Use of undeclared identifier ‘_refreshControl’; did you mean ‘refreshControl’?

@implementation RCTCustomScrollView
{
  __weak UIView *_dockedHeaderView;
  RCTRefreshControl *_refreshControl;  // 加入此行
}

apache启用gzip压缩的实现方法

一、gzip介绍

Gzip是一种流行的文件压缩算法,现在的应用十分广泛,尤其是在Linux平台。当应用Gzip压缩到一个纯文本文件时,效果是非常明显的,大约可以减少70%以上的文件大小。这取决于文件中的内容。

利用Apache中的Gzip模块,我们可以使用Gzip压缩算法来对Apache服务器发布的网页内容进行压缩后再传输到客户端浏览器。这样经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可以加快网页加载的速度。

网页加载速度加快的好处不言而喻,除了节省流量,改善用户的浏览体验外,另一个潜在的好处是Gzip与搜索引擎的抓取工具有着更好的关系。例如 Google就可以通过直接读取gzip文件来比普通手工抓取更快地检索网页。在Google网站管理员工具(Google Webmaster Tools)中你可以看到,sitemap.xml.gz 是直接作为Sitemap被提交的。

而这些好处并不仅仅限于静态内容,PHP动态页面和其他动态生成的内容均可以通过使用Apache压缩模块压缩,加上其他的性能调整机制和相应的服务器端 缓存规则,这可以大大提高网站的性能。因此,对于部署在Linux服务器上的PHP程序,在服务器支持的情况下,我们建议你开启使用Gzip Web压缩。

二、Web服务器处理HTTP压缩的过程如下:

1. Web服务器接收到浏览器的HTTP请求后,检查浏览器是否支持HTTP压缩(Accept-Encoding 信息);

2. 如果浏览器支持HTTP压缩,Web服务器检查请求文件的后缀名;

3. 如果请求文件是HTML、CSS等静态文件,Web服务器到压缩缓冲目录中检查是否已经存在请求文件的最新压缩文件;

4. 如果请求文件的压缩文件不存在,Web服务器向浏览器返回未压缩的请求文件,并在压缩缓冲目录中存放请求文件的压缩文件;

5. 如果请求文件的最新压缩文件已经存在,则直接返回请求文件的压缩文件;

6. 如果请求文件是动态文件,Web服务器动态压缩内容并返回浏览器,压缩内容不存放到压缩缓存目录中。

下面是两个演示图:

未使用Gzip:

开启使用Gzip后:

三、实施

Apache上利用Gzip压缩算法进行压缩的模块有两种:mod_gzip 和mod_deflate。 要使用Gzip Web压缩,请首先确定你的服务器开启了对这两个组件之一的支持。在Linux服务器上,现在已经有越来越多的空间商开放了对它们的支持,有的甚至是同时 支持这两个模块的。例如目前Godaddy、Bluehost及DreamHosts等空间商的服务器都已同时支持mod_gzip 和mod_deflate。

虽然使用Gzip同时也需要客户端浏览器的支持,不过不用担心,目前大部分浏览器都已经支持Gzip了,如IE、Mozilla Firefox、Opera、Chrome等。

通过查看HTTP头,我们可以快速判断使用的客户端浏览器是否支持接受gzip压缩。若发送的HTTP头中出现以下信息,则表明你的浏览器支持接受相应的gzip压缩:

Accept-Encoding: gzip 支持mod_gzip
Accept-Encoding: deflate 支持mod_deflate

Accept-Encoding: gzip,deflate 同时支持mod_gzip 和mod_deflate  在apache2.0以上(包括apache2.0)的版中gzip压缩使用的是mod_deflate模块,下面是具体配置步骤 如下:

1、修改Apache的http.conf文件,去除mod_deflate.so前面的注释

复制代码代码如下:
LoadModule deflate_module modules/mod_deflate.so

2、在根目录中新建.htaccess文件,定制压缩规则

复制代码代码如下:
#GZIP压缩模块配置
<ifmodule mod_deflate.c>
#启用对特定MIME类型内容的压缩
SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png|exe|t?gz|zip|bz2|sit|rar|pdf|mov|avi|mp3|mp4|rm)$ no-gzip dont-vary #设置不对压缩的文件
AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml application/x-httpd-php application/x-javascript #设置对压缩的文件
</ifmodule>

3、对指定的文件配置缓存的生存时间,去除mod_headers.so模块前面的注释

复制代码代码如下:
LoadModule headers_module modules/mod_headers.so

4、在根目录中新建.htaccess文件,定制压缩规则

复制代码代码如下:
#文件缓存时间配置
<FilesMatch “.(flv|gif|jpg|jpeg|png|ico|swf|js|css)$”>
Header set Cache-Control “max-age=2592000”
</FilesMatch>

里面的文件MIME类型可以根据自己情况添加,至于PDF 、图片、音乐文档之类的这些本身都已经高度压缩格式,重复压缩的作用不大,反而可能会因为增加CPU的处理时间及浏览器的渲染问题而降低性能。所以就没必要再通过Gzip压缩。通过以上设置后再查看返回的HTTP头,出现以下信息则表明返回的数据已经过压缩。即网站程序所配置的Gzip压缩已生效。

Content-Encoding: gzip注:不管使用mod_gzip 还是mod_deflate,此处返回的信息都一样。因为它们都是实现的gzip压缩方式。

除此之外,还可以通过一些在线检查工具http://tool.chinaz.com/Gzips/来检测你的网站内容是否已经过Gzip压缩。

四、mod_gzip 和mod_deflate的主要区别是什么?使用哪个更好呢?

首先一个区别是安装它们的Apache Web服务器版本的差异。Apache 1.x系列没有内建网页压缩技术,所以才去用额外的第三方mod_gzip 模块来执行压缩。而Apache 2.x官方在开发的时候,就把网页压缩考虑进去,内建了mod_deflate 这个模块,用以取代mod_gzip。虽然两者都是使用的Gzip压缩算法,它们的运作原理是类似的。

第二个区别是压缩质量。mod_deflate 压缩速度略快而mod_gzip 的压缩比略高。一般默认情况下,mod_gzip 会比mod_deflate 多出4%~6%的压缩量。

那么,为什么使用mod_deflate?第三个区别是对服务器资源的占用。 一般来说mod_gzip 对服务器CPU的占用要高一些。mod_deflate 是专门为确保服务器的性能而使用的一个压缩模块,mod_deflate 需要较少的资源来压缩文件。这意味着在高流量的服务器,使用mod_deflate 可能会比mod_gzip 加载速度更快。

不太明白?简而言之,如果你的网站,每天不到1000独立访客,想要加快网页的加载速度,就使用mod_gzip。虽然会额外耗费一些服务器资源, 但也是值得的。如果你的网站每天超过1000独立访客,并且使用的是共享的虚拟主机,所分配系统资源有限的话,使用mod_deflate 将会是更好的选择。

另外,从Apache 2.0.45开始,mod_deflate 可使用DeflateCompressionLevel 指令来设置压缩级别。该指令的值可为1(压缩速度最快,最低的压缩质量)至9(最慢的压缩速度,压缩率最高)之间的整数,其默认值为6(压缩速度和压缩质 量较为平衡的值)。这个简单的变化更是使得mod_deflate 可以轻松媲美mod_gzip 的压缩。

P.S. 对于没有启用以上两种Gzip模块的虚拟空间,还可以退而求其次使用php的zlib函数库(同样需要查看服务器是否支持)来压缩文件,只是这种方法使用起来比较麻烦,而且一般会比较耗费服务器资源,请根据情况慎重使用。详细  php启用zlib压缩文件

无觅相关文章插件,快速提升流量