1

我正在做一个个人项目 - 使用 php 从 MySQL 获取数据,然后将其编码为 JSON 格式(包括列),然后通过 Ajax 将其加载到谷歌数据表中以进行可视化。

项目进展顺利,但我在 php.ini 中通过纯字符串操作进行了 JSON 编码。只需一条 SQL 和一个 php 函数即可为图表制作多个数据源。

我觉得我需要这个的原因有 1 个不好的原因,还有 2 个真正的原因 -

  • 我是 Javascript 的新手
  • JSON_ENCODE(php 函数)似乎产生了日期值所需的错误格式。
    • 它输出日期(和日期时间)为:“2013-01-01 01:00:00”
    • 谷歌的文档似乎需要:“日期(2013,1,1,0,0,0)”
  • 并且 JSON_Encode 没有为所需的列生成输出 - 包括根据 MySQL 结果数据类型分配数据类型。

问题:

在 JSON 的日期格式和列输出的上下文中(包括基于结果的数据类型)——我能比纯字符串操作更容易解决这些问题吗?

我已经在下面发布了我的代码 - 虽然很可怕 - 它的工作就像一个魅力。如果由于某种原因我确实做了一些好事,欢迎社区使用它。

它是 3 个 php 文件(尽管最后一个应该是 html),第一个文件只是填充了要在第二页中使用的自定义函数。

第二个 php 文件以 JSON/GoogleChart 格式从 My_SQL (echo DATA;) 转储数据。

最后一个文件/页面使用 ajax 从第二页获取数据,并将其插入到带注释的时间轴中。Jquery 设置在第三页,第一页是 MySQL 连接,第二页是你的 SQL。

<?php
// First Page/File: mysql_gc_functions.php
function mysql_loadresult($sql, $type){

// $sql - a string containing SQL to run against database
// $type - 0 for standard array load, 1 for JSON formatted string

$debug = false;

$result = mysql_query($sql) or die(mysql_error());
$numfields = mysql_num_fields($result);
$numrows = mysql_num_rows($result);
$br = '</br>';

$arr; // Array to Load Data Into where first index will contain headers
      // Where x is the column and y is the row
      // Row '0' contains Header Names

$datatypes; // Array to Load in Data Types

// Standard Array Loading

// Load Field Names
for ($x=0; $x < $numfields; $x++){
    $arr[$x][0] = mysql_field_name($result,$x);
    $datatypes[$x] = mysql_field_type($result,$x);
    if($debug == true){echo 'data type for ' . $arr[$x][0] . ': ' . $datatypes[$x] . '</br>';}
}

$y = 0; // Row Index
while ($data = mysql_fetch_array($result, MYSQL_NUM)) {// For Each Row
    $y++;
    for ($x=0; $x<$numfields; $x++){ // For Each Field
        $arr[$x][$y] = $data[$x]; // Load Query into php array
    }
}

// JSON formatted string
if ($type == 1) {
    /* JSON Format Example
    {
      "cols": [
            {"label":"Topping","type":"string"},
            {"label":"Slices","type":"number"}
          ],
      "rows": [
            {"c":[{"v":"Mushrooms"},{"v":3},
            {"c":[{"v":"Onions"},{"v":1}]},
            {"c":[{"v":"Olives"},{"v":1}]},
            {"c":[{"v":"Zucchini"},{"v":1}]},
            {"c":[{"v":"Pepperoni"},{"v":2}]}
          ]
    }

    mysql data type / google field type / Json value example:

        date:               date:           "Date(2012,12,1)"
        datetime:           datetime:       "Date(2012,12,1,23,59,59)"  <- Y,M,D,H,M,S - can do milliseconds as well (but not built)
        number:             int/real:       123456
        everything else:    string:         "EXAMPLE TEXT"

    */      
    $sColJason = '{"cols":[';
    $eColJason = '],';
    $ColExprS = '{"label":"';
    $ColExprE = '","type":"XXX"}';
    $colbuild = '';

    // Build Column Structure for JSON
    for ($x=0;$x<$numfields;$x++){

        if ($datatypes[$x] == 'date'){
            $tvar = str_replace('XXX', 'date', $ColExprE);
        } else if ($datatypes[$x] == 'int' OR $datatypes[$x] == 'real'){
            $tvar = str_replace('XXX','number',$ColExprE);
        } else if ($datatypes[$x] == 'datetime'){
            $tvar = str_replace('XXX','datetime',$ColExprE);
        } else {
            $tvar = str_replace('XXX','string',$ColExprE);
        }

        $str = $ColExprS . $arr[$x][0] . $tvar;
        if ($x != ($numfields - 1)){
            $str = $str . ",";
        }
        $colbuild = $colbuild . $str;
    }

    if($debug == true){echo $sColJason . $colbuild . $eColJason . '</br>';}

    $sRowJason = '"rows": [';
    $eRowJason = ']}';
    $RowExpr = '{"v":"XXX"}';
    $RowStart = '{"c":[';
    $RowEnd = ']}';
    $RowBuild = '';

    // Build Row Structure for JSON
    for ($y = 1; $y<$numrows;$y++){
        // build each column of row (field of record)
        $RowFieldBuild = '';
        for ($x=0;$x<$numfields;$x++){  
            $var = $arr[$x][$y];

            // assess how the data type needs to be treated
            if ($datatypes[$x] == 'date'){
                $var = mysql_googledate($var);
            } else if ($datatypes[$x] == 'int' OR $datatypes[$x] == 'real'){
                $var = $var;
            } else if ($datatypes[$x] == 'datetime') {
                $var = mysql_googleDtTm($var);
            } else {
                $var = '"' . $var . '"';
            }

            // concatenate the row string with populated values
            $RowFieldBuild = $RowFieldBuild . str_replace('"XXX"',$var,$RowExpr);
            if ($x != ($numfields-1)){
                $RowFieldBuild = $RowFieldBuild . ',';
            }
        }
        // Encapsulate the Record
        $RowBuild = $RowBuild . $RowStart . $RowFieldBuild . $RowEnd;
        if($y != ($numrows-1)){
            $RowBuild = $RowBuild . ',';
        }
    }
    // Encapsulate Entire Row Data
    $RowBuild = $sRowJason . $RowBuild . $eRowJason;
    if($debug == true){echo $RowBuild . '</br>';}

    return ($sColJason . $colbuild . $eColJason . $RowBuild);

} else { // Return Standard Array of Table Data
    return $arr;
}
}

function mysql_googledate($var){
$arr = preg_split("/-/",$var);
$month = intval($arr[1]);
$newStr = '"Date(' . $arr[0] . ',' . $month . ',' . $arr[2] . ')"';
return $newStr;
}
function mysql_googleDtTm($var){
$arr = preg_split("/-/",$var);
$tmArr = preg_split("/:/",$arr[2]);
$cm = ',';

$yr = intval($arr[0]);
$mon = intval($arr[1]);
$day = intval(substr($arr[2],0,2));

$hr = intval(substr($tmArr[0],-2));
$min = intval($tmArr[1]);
$sec = intval($tmArr[2]);

$newStr = '"Date(' . $yr . $cm . $mon . $cm . $day . $cm . $hr . $cm . $min . $cm . $sec . ')"';
return $newStr;
}

function mysql_localcon(){
$con = mysql_connect("localhost","root","1234");
if (!$con)  {
    die('Could not connect: ' . mysql_error());
}
return $con;
}

?>

<?php
// Second Page/File: data_ATL.php
Include('mysql_gc_functions.php');
  $sql = 'SELECT DATE_FIELD, VALUE_FIELD FROM DATABASE.TABLE';
  $con=mysql_localcon();
  $dataJason = mysql_loadresult($sql, 1);
  echo $dataJason;
?>

// THIS IS THE FINAL (3rd) OUTPUT FILE/PAGE - DISPLAYS ANNOTATED TIME LINE
<html>  
<head>   
<script type='text/javascript' src='http://www.google.com/jsapi'></script>
<script type="text/javascript" src="jquery.js"></script>  
<script type='text/javascript'>    
    google.load('visualization', '1', {'packages':['annotatedtimeline']});  
    google.setOnLoadCallback(drawChart);   
    function drawChart() {
        var jsonData = $.ajax({
            url: "data_ATL.php",
            dataType:"json",
            async: false
            }).responseText;

        var data = new google.visualization.DataTable(jsonData);    
        var chart = new google.visualization.AnnotatedTimeLine(document.getElementById('chart_div'));    
        chart.draw(data, 
            {
                displayAnnotations: true,
                annotationsWidth: 20,
                scaleType: 'maximized'      
            }
        );
    }
</script>  
</head>
<body>  
<div id='chart_div' style='width: 700px; height: 240px;'></div> 
</body>
</html>
4

1 回答 1

1

我最近有这个完全相同的任务,并且能够创建一个基于 MySQL 查询返回的任何数据生成 Google 数据表的函数。我只使用json_encode()构建 JSON 有效负载- 没有特定的字符串操作。注意,我使用 mysqli 而不是 mysql,所以下面的一些内容可能与 mysql 略有不同。

以下是一些不太明显的方面:

  • 为了确定 Google DataTable 列的“类型”,我使用了mysqli_fetch_fields() (http://php.net/manual/en/mysqli-result.fetch-fields.php)返回的数组的“类型”值. 然后,我编写了一个小函数,将这个 mysqli 类型与 Google 的 DataTable API 的等价物相匹配。因此,例如,如果 mysqli_fetch_fields() 返回:

    [0] => stdClass Object
    (
        [name] => Date
        [orgname] => date
        [table] => c
        [orgtable] => users
        [def] => 
        [db] => main
        [catalog] => def
        [max_length] => 10
        [length] => 10
        [charsetnr] => 63
        [flags] => 20617
        [type] => 10
        [decimals] => 0
    )
    

    您可以看到类型值为 10,对应于MYSQLI_TYPE_DATE。可以在此处找到类型常量的完整列表:http: //php.net/manual/en/mysqli.constants.php

  • 日期类型确实需要一些操作,因为 JSON 不支持 Javascript 日期对象(但 Google 的 API 确实支持“日期(Y,m,d,[h,i,s])”,正如您所指出的。需要注意的一点是MySQL 日期的月份参数应减 1,因为 Javascript 日期对象从第 0 个月开始。为了提取日期,我使用了这个:

    $mysql_date = explode("-", $row[$i]);
    $mysql_date[1] = $mysql_date[1] - 1;
    if ($mysql_date[1] < 0) $mysql_date[1] = 11;
    $mysql_date = implode(",", $mysql_date);
    $value = "Date(" . $mysql_date . ")";
    array_push($c, array("v" => $value));
    

    preg_split工作正常,但请注意它速度较慢(如果您有一个非常大的数据集,这只是一个问题)。更多信息在这里: http: //micro-optimization.com/explode-vs-preg_split

  • 到目前为止,唯一的字符串操作是处理日期,其他所有内容都存储在 PHP 数组中。收集完所有数据后,您可以调用 json_encode()。这样做的问题是,对于为 Google 表定义为“数字”的列, json_encode() 倾向于返回用双引号括起来的数字。为了强制数字被这样对待,我使用了一个简单的正则表达式:

    $json = json_encode($j);
    $json = preg_replace('/"(-?\d+\.?\d*)"/', '$1', $json);
    

希望这可以帮助!

于 2013-01-25T10:56:22.350 回答