PHP, bir dize, bir matematik problemi / ifade, Çözme

4 Cevap php

Kullanıcı gibi bir matematik problemini (ifade) girebilir 5 + 654, 6 ^ 24, 2!, sqrt(543), log(54) , sin 5, sin(50). Bazı yeniden biçimlendirme (örn. değişim sin 5 sin(5) içine), ve bir eval yaptıktan sonra, PHP bana doğru sonucu verir:

$problem = "5 + 5324";
eval("$result = " . $problem);
echo $problem . " = " . $result;

Ancak, bu oldukça güvensiz:

/* If you read this, please, plz don't be stupid and DO NOT EXECUTE this code!!!!! */
$problem = "shell_exec('rm -rf /')";
eval("$result = " . $problem); /* Nukes system */
echo $problem . " = " . $result;

Herkes güvenli yukarıdaki örneklerde olduğu gibi bir matematik soru, ayrıştırma ve çözme bana doğru yönde işaret edebilir? Teşekkürler.


Btw arasında eval sadece ortak bir yazım hatası değil evil?

4 Cevap

bcParserPHP bir seçenektir. It güvenli vb eval kullanmak değildir. http://www.facebook.com/pages/Math-Parser-Library/123312041160280

İdeal olarak, ben onun bölüme formülü ayrıştırmak ve bir o denklemi çalıştırabilir dilbilgisi ayrıştırıcı / lexer motor çeşit oluşturmak zorunda düşünüyorum.

Bu şekilde herhangi bir kötü niyetli fonksiyonlar sadece göz ardı edileceği, ve sistem bir hata dönebilir.

PHPExcel içinde hesaplama motorunda bir göz atın ... Bu hesaplanabilir ki (yerine bir ikili operatör daha güç gibi LOG (gibi fonksiyonları dahil), ve 2 ^ 3) en kalıplaşmış ifadeler işleyebilir güvenli bir formül çözümleyici Excel kendisi tarafından.

Peki hemen hemen bu durumda kendi hesap makinesi uygulamak gerekir - bu yüzden burada bir kez iş görüşmesine de aldım benim kodudur. Benim için gerçekten çok eski şeyler var ama size bazı fikirler verebilir düşündüm hatırlıyorum:

<?php
if(isset($_POST['inp'])) {
    $time_start = microtime(true);

    $inp = preg_replace(array('/\s+/', '/Pi/', '/e/', '/T/', '/G/', '/M/', '/k/', '/m/', '/u/', '/n/', '/p/', '/f/'), 
                        array('', M_PI, exp(1), '*'. 1e12, '*'. 1e9, '*'. 1e6, '*'. 1e3, '*'. 1e-3, '*'. 1e-6, '*'. 1e-9, '*'. 1e-12, '*'. 1e-15),
                         $_POST['inp']);


    function rectify($exp, $mod = "+") {

        $res = recCalc($exp);
        debug("Pre rectify", $res);
        if($mod == '-') {
            $res *= -1;
        }
        debug("Post rectify", $res);
        return $res;
    }


    function do_error($str) {
        die($str);
        return false;
    }


    function recCalc($inp) {
        debug("RecCalc input", $inp);   

        $p = str_split($inp);
        $level = 0;

        foreach($p as $num) {
            if($num == '(' && ++$level == 1) {
                $num = 'BABRAX';

            } elseif($num == ')' && --$level == 0) {
                $num = 'DEBRAX';
            }
            $res[] = $num;

        }

        if($level != 0) {
            return do_error( 'Chyba: špatný počet závorek');
        }

        $res = implode('', $res);

        $res = preg_replace('#([\+\-]?)BABRAX(.+?)DEBRAX#e', "rectify('\\2', '\\1')", $res);

        debug("After parenthesis proccessing", $res);
        preg_match_all('#[+-]?([^+-]+)#', $res, $ar, PREG_PATTERN_ORDER);

        for($i = 0; $i <count($ar[0]); $i++) {
              $last = substr($ar[0][$i], -1, 1); 
              if($last == '/' || $last == '*' || $last == '^' || $last == 'E') {
                    $ar[0][$i] = $ar[0][$i].$ar[0][$i+1];
                    unset($ar[0][$i+1]);
              }
        }

        $result = 0;
        foreach($ar[0] as $num) {
            $result += multi($num);
        }
        debug("RecCalc output", $result);
        return $result;
    }

            function multi($inp) {
        debug("Multi input", $inp);

        $inp = explode(' ', ereg_replace('([\*\/\^])', ' \\1 ', $inp));

        foreach($inp as $va) {
            if($va != '*' && $va != '/' && $va != '^') {
                $v[] = (float)$va;
            } else {
                $v[] = $va;
            }
        }
        $inp = $v;
        //predpokladame, ze prvni prvek je cislo, ktere budeme dale nasobit
        $res = $inp[0];
        for($i = 1; $i< count($inp); $i++) {

            if($inp[$i] == '*') {
                $res *= $inp[$i + 1];
            } elseif($inp[$i] == '/') {
                if($inp[$i + 1] == 0) do_error('Dělení nulou');

                $res /= $inp[$i + 1];
            } elseif($inp[$i] == '^') {
                $res = pow($res, $inp[$i + 1]);
            }
        }
        debug("Multi output", $res);
        return $res;
    }


    function debug($msg, $var) {
        if(isset($_POST['out']) && $_POST['out'] == '1') {
            echo "\n".$msg.": ".$var;
        }
    }
    echo '<pre>';


    if(eregi('(^[\*\/\+\^])|[a-dg-z \?<>;:"\'\\|\}\{_]|([\*\/\+\-\^]$)', $inp)) {
        do_error('Nalezen neplatný či nesmyslný znak. Překontorlujte si prosím syntax.');
    }

    $result = recCalc($inp);

    $time_end = microtime(true);
    $time = ($time_end - $time_start) *1000;
    $time .= 'ms';

    echo "\n<strong>".$result."</strong>";
    debug('Execution time', $time);
    echo '</pre>';

} else {


?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Calculator</title>
<style type="text/css">
<!--
body {
    font: 100% Verdana, Arial, Helvetica, sans-serif;
    background: #666666;
    margin: 0; /* it's good practice to zero the margin and padding of the body element to account for differing browser defaults */
    padding: 0;
    text-align: center; /* this centers the container in IE 5* browsers. The text is then set to the left aligned default in the #container selector */
    color: #000000;
}
.oneColElsCtr #container {
    width: 46em;
    background: #FFFFFF;
    margin: 0 auto; /* the auto margins (in conjunction with a width) center the page */
    border: 1px solid #000000;
    text-align: left; /* this overrides the text-align: center on the body element. */
}
.oneColElsCtr #mainContent {
    padding: 0 20px; /* remember that padding is the space inside the div box and margin is the space outside the div box */
}
.noshow {
    display: none;
}
-->
</style>
<link rel="stylesheet" href="styles/COHEN_style.css"/>
<script src="scripts/spry/SpryData.js"></script>
<!--<script src="scripts/spry/xpath.js"></script>-->
<script src="scripts/spry/SpryUtils.js"></script>
<script src="scripts/spry/SpryDOMUtils.js" type="text/javascript"></script>
<script src="scripts/spry/SpryCollapsiblePanel.js" type="text/javascript"></script>

<script type="text/javascript">
<!--
function updateResultDiv(req) 
    {
        Spry.Utils.setInnerHTML('result', req.xhRequest.responseText);
    }
function submitit() {
    if(document.getElementById('auto').checked) {
        Spry.Utils.submitForm(document.getElementById('calc'), updateResultDiv);
    }
}
-->
</script>
<link href="scripts/spry/SpryCollapsiblePanel.css" rel="stylesheet" type="text/css" />
</head>

<body class="oneColElsCtr">

<div id="container">
  <div id="mainContent">
    <h1>Calculator</h1>
    <form method="post" id="calc" onsubmit="return Spry.Utils.submitForm(document.getElementById('calc'), updateResultDiv);">
    <input type="text" name="inp" size="80" value="" onkeyup="submitit()"/><br />
    <input type="checkbox" value="1" name="out" /><label>Debug</label>  <input onclick="Spry.$$('#submit').toggleClassName('noshow');" checked="checked" type="checkbox" value="1" id="auto" /><label for="auto">Count automatically</label><br />
    <input class="noshow" value="Počítej" type="submit" id="submit"  />
    </form>
    <div id="result">

    </div>
</div>
</div>
</body>
</html>

Ayrıca ben garip yorumlar için çok üzgünüm kontrol yazdım.