Index: branches/version-2_5-dev/data/class/pages/admin/products/LC_Page_Admin_Products.php
===================================================================
--- branches/version-2_5-dev/data/class/pages/admin/products/LC_Page_Admin_Products.php	(revision 19670)
+++ branches/version-2_5-dev/data/class/pages/admin/products/LC_Page_Admin_Products.php	(revision 19742)
@@ -250,6 +250,8 @@
 
                         // CSVを送信する。正常終了の場合、終了。
-                        list($fime_name, $data) = $objCSV->sfDownloadProductsCsv($where, $arrval, $order);
-                        $this->sendResponseCSV($fime_name, $data);
+                        $objCSV->sfDownloadProductsCsv($where, $arrval, $order, true);
+                        // FIXME: sendResponseに渡した方が良いのか？
+//                        $data = $objCSV->sfDownloadProductsCsv($where, $arrval, $order);
+//                        $this->sendResponseCSV($fime_name, $data);
                         exit;
                         break;
Index: branches/version-2_5-dev/data/class/helper/SC_Helper_CSV.php
===================================================================
--- branches/version-2_5-dev/data/class/helper/SC_Helper_CSV.php	(revision 19730)
+++ branches/version-2_5-dev/data/class/helper/SC_Helper_CSV.php	(revision 19742)
@@ -120,7 +120,16 @@
         $data = $objCSV->lfGetCSV("dtb_order", $where, $option, $arrval, $arrCsvOutputCols, $arrCsvOutputConvs);
     }
+    
+    //  CSV作成 コールバック関数
+    function cbOutputProductCSV($data) {
+        $line = $this->sfArrayToCSV($data);
+        $line = mb_convert_encoding($line, 'SJIS-Win');
+        $line .= "\r\n";
+        fwrite($this->fpOutput, $line);
+        return true;
+    }
 
     // CSVを送信する。(商品)
-    function sfDownloadProductsCsv($where, $arrval, $order) {
+    function sfDownloadProductsCsv($where, $arrval, $order, $is_download = false) {
 
         // CSV出力タイトル行の作成
@@ -131,60 +140,36 @@
         $objQuery = new SC_Query();
         $objQuery->setOrder($order);
-
-        /*
-         * FIXME
-         * パフォーマンスが出ないため,
-         * SC_Product::getProductsClassByProductIds() を使用した実装に変更
-         */
-        $dataRows = $objQuery->select(
-             SC_Utils_Ex::sfGetCommaList($arrOutputCols, true, array('category_id'))
-            ,'vw_product_class AS prdcls'
-            ,$where
-            ,$arrval
-        );
-        
-        // 規格分類名一覧
-        if (in_array('classcategory_id1', $arrOutputCols) || in_array('classcategory_id2', $arrOutputCols)) {
-            $objDb = new SC_Helper_DB_Ex();
-            $arrClassCatName = $objDb->sfGetIDValueList("dtb_classcategory", "classcategory_id", "name");
-        }
-
-        $outputArray = array();
-        
-        // ヘッダ行
-        $outputArray[] = $arrOutput['disp_name'];
-        
-        $objQuery = new SC_Query();
-        // データ行
-        foreach ($dataRows as $row) {
-            // 規格名1
-            if (in_array('classcategory_id1', $arrOutputCols)) {
-                $row['classcategory_id1'] = $arrClassCatName[$row['classcategory_id1']];
-            }
-
-            // 規格名2
-            if (in_array('classcategory_id2', $arrOutputCols)) {
-                $row['classcategory_id2'] = $arrClassCatName[$row['classcategory_id2']];
-            }
-
-            // カテゴリID
-            if (in_array('category_id', $arrOutputCols)) {
-                $row['category_id'] = $objQuery->getCol(
-                    "category_id",
-                    "dtb_product_categories",
-                    "product_id = ?",
-                    array($row['product_id'])
-                );
-            }
-
-            $outputArray[] = $row;
-        }
-        
-        // CSVを送信する。
-        #$this->lfDownloadCsv($outputArray);
-        return $this->lfGetCsv2($outputArray);
-        
-        // 成功終了
-        #return true;
+        
+        $objProduct = new SC_Product();
+        $cols = SC_Utils_Ex::sfGetCommaList($arrOutputCols, true);
+        $sql = $objQuery->getSql($cols, $objProduct->prdclsSQL(),$where);
+        $header = $this->sfArrayToCSV($arrOutput['disp_name']);
+        $header = mb_convert_encoding($header, 'SJIS-Win');
+        $header .= "\r\n";
+        
+        //テンポラリファイル作成
+        // TODO: パフォーマンス向上には、ストリームを使うようにすると良い
+        //  環境要件がバージョン5.1以上になったら使うように変えても良いかと
+        //  fopen('php://temp/maxmemory:'. (5*1024*1024), 'r+');
+        $tmp_filename = tempnam(CSV_TEMP_DIR, 'product_csv');
+        $this->fpOutput = fopen($tmp_filename, "w+");
+
+        fwrite($this->fpOutput, $header);
+
+        $objQuery->doCallbackAll(array(&$this, 'cbOutputProductCSV'), $sql, $arrval);
+
+        fclose($this->fpOutput);
+
+        if($is_download) {
+            // CSVを送信する。
+            $this->lfDownloadCSVFile($tmp_filename,"product_");
+            $res = true;
+        }else{
+            $res = SC_Utils_Ex::sfReadFile($tmp_filename);
+        }
+        
+        //テンポラリファイル削除
+        unlink($tmp_filename);
+        return $res;
     }
 
@@ -498,4 +483,21 @@
         }
     }
+    
+    /**
+     * CSVファイルを送信する。
+     */
+    function lfDownloadCSVFile($filepath, $prefix = "") {
+        $file_name = $prefix . date("YmdHis") . ".csv";
+        
+        /* HTTPヘッダの出力 */
+        Header("Content-disposition: attachment; filename=${file_name}");
+        Header("Content-type: application/octet-stream; name=${file_name}");
+        Header("Cache-Control: ");
+        Header("Pragma: ");
+        
+        /* データを出力 */
+        // file_get_contentsはメモリマッピングも自動的に使ってくれるので高速＆省メモリ
+        echo file_get_contents($filepath);
+    }
 
     /**
Index: branches/version-2_5-dev/data/class/SC_Query.php
===================================================================
--- branches/version-2_5-dev/data/class/SC_Query.php	(revision 19732)
+++ branches/version-2_5-dev/data/class/SC_Query.php	(revision 19742)
@@ -216,4 +216,37 @@
         return $this->query($str, $arrval);
     }
+    
+    /**
+     * クエリを実行し、結果行毎にコールバック関数を適用する
+     *
+     * @param callback $function コールバック先
+     * @param string $sql SQL クエリ
+     * @param array $arrVal プリペアドステートメントの実行時に使用される配列。配列の要素数は、クエリ内のプレースホルダの数と同じでなければなりません。 
+     * @param integer $fetchmode 使用するフェッチモード。デフォルトは DB_FETCHMODE_ASSOC。
+     * @return boolean 結果
+     */
+    function doCallbackAll($cbFunc, $sql, $arrval = array(), $fetchmode = MDB2_FETCHMODE_ASSOC) {
+
+        $sql = $this->dbFactory->sfChangeMySQL($sql);
+
+        $sth =& $this->prepare($sql);
+        if (PEAR::isError($sth) && $this->force_run) {
+            return;
+        }
+
+        $affected =& $this->execute($sth, $arrval);
+        if (PEAR::isError($affected) && $this->force_run) {
+            return;
+        }
+        
+        while($data = $affected->fetchRow($fetchmode)) {
+            $result = call_user_func($cbFunc, &$data);
+            if($result === false) {
+                break;
+            }
+        }
+        $sth->free();
+        return $result;
+    }
 
     /**
Index: branches/version-2_5-dev/data/class/SC_Product.php
===================================================================
--- branches/version-2_5-dev/data/class/SC_Product.php	(revision 19740)
+++ branches/version-2_5-dev/data/class/SC_Product.php	(revision 19742)
@@ -716,4 +716,58 @@
 
     /**
+     * 商品規格詳細の SQL を取得する.
+     *
+     * MEMO: 2.4系 vw_product_classに相当(?)するイメージ
+     *
+     * @param string $where 商品詳細の WHERE 句
+     * @return string 商品規格詳細の SQL
+     */
+    function prdclsSQL($where = "") {
+        $whereCause = "";
+        if (!SC_Utils_Ex::isBlank($where)) {
+            $whereCause = " WHERE " . $where;
+        }
+        $sql = <<< __EOS__
+        (
+             SELECT dtb_products.*,
+                    dtb_products_class.product_class_id,
+                    dtb_products_class.class_combination_id,
+                    dtb_products_class.product_type_id,
+                    dtb_products_class.product_code,
+                    dtb_products_class.stock,
+                    dtb_products_class.stock_unlimited,
+                    dtb_products_class.sale_limit,
+                    dtb_products_class.price01,
+                    dtb_products_class.price02,
+                    dtb_products_class.deliv_fee,
+                    dtb_products_class.point_rate,
+                    dtb_products_class.down_filename,
+                    dtb_products_class.down_realfilename,
+                    dtb_class_combination.parent_class_combination_id,
+                    dtb_class_combination.classcategory_id,
+                    dtb_class_combination.level as classlevel,
+                    Tpcm.classcategory_id as parent_classcategory_id,
+                    Tpcm.level as parent_classlevel,
+                    Tcc1.class_id as class_id,
+                    Tcc1.name as classcategory_name,
+                    Tcc2.class_id as parent_class_id,
+                    Tcc2.name as parent_classcategory_name
+             FROM dtb_products
+                 LEFT JOIN dtb_products_class
+                     ON dtb_products.product_id = dtb_products_class.product_id
+                 LEFT JOIN dtb_class_combination
+                     ON dtb_products_class.class_combination_id = dtb_class_combination.class_combination_id
+                 LEFT JOIN dtb_class_combination as Tpcm
+                     ON dtb_class_combination.parent_class_combination_id = Tpcm.class_combination_id
+                 LEFT JOIN dtb_classcategory as Tcc1
+                     ON dtb_class_combination.classcategory_id = Tcc1.classcategory_id
+                 LEFT JOIN dtb_classcategory as Tcc2
+                     ON Tpcm.classcategory_id = Tcc2.classcategory_id
+        ) as prdcls
+__EOS__;
+        return $sql;
+    }
+    
+    /**
      * 商品規格ID1、2に紐づいた,product_class_idを取得する.
      *
