带有可选表单字段的动态准备插入语句

时间:2015-11-17 01:24:15

标签: php forms prepared-statement

所以我在几年前发现了这个问题/答案,它与我的需求相似,但我认为我并没有正确地理解它。如果由于表单中的可选字段导致$_POST字段计数和数据库字段数不相同,会发生什么?

function insertToDB($params, $db) { //Pass array and db

    $fields = array();
    $conn = new mysqli('localhost', 'root', 'root', 'db') or die('XXX');     
    $stmt =  $conn->stmt_init();
    $stmt->prepare("SELECT * FROM ".$db); 
    $stmt->execute();
    $meta =  $stmt->result_metadata();
    while ($field = $meta->fetch_field()) { 
         $fields[] = $field->name;   
    }

    $fields = implode(", ", $fields);


    $placeholders = implode(',', array_fill(0, count($params), '?'));

    $types = '';
    foreach($params as $value) {
        $types.= substr(strtolower(gettype($value)), 0, 1); 
    }

    $ins = "INSERT INTO MYDB (".$fields.") VALUES (".$placeholders.")"; 

    $bind_names[] = $types; 
    for ($i = 0; $i < count($params); $i++) { 
        $bind_name = 'bind' . $i;
        $$bind_name = $params[$i];
        $bind_names[] = &$$bind_name;
    }
    if ($stmt->prepare($ins)) {
            call_user_func_array(array($stmt,'bind_param'),$bind_names); 
            $insresult = $stmt->execute(); 
    }
    return $insresult;
    $stmt->close();
}

2 个答案:

答案 0 :(得分:0)

如果某个字段是可选字段,那么你应该检查是否设置了$ _POST,你可以这样做:

[2015-11-16T21:03:24.749Z] INFO  [2680]  - [Application update/AppDeployStage0/AppDeployPreHook/03deploy.py] : Starting activity...
[2015-11-16T21:03:27.024Z] INFO  [2680]  - [Application update/AppDeployStage0/AppDeployPreHook/03deploy.py] : Activity execution failed, because: Collecting psycopg2==2.6.1 (from -r /opt/python/ondeck/app/requirements.txt (line 1))
    Using cached psycopg2-2.6.1.tar.gz
      Complete output from command python setup.py egg_info:
      running egg_info
      creating pip-egg-info/psycopg2.egg-info
      writing top-level names to pip-egg-info/psycopg2.egg-info/top_level.txt
      writing dependency_links to pip-egg-info/psycopg2.egg-info/dependency_links.txt
      writing pip-egg-info/psycopg2.egg-info/PKG-INFO
      writing manifest file 'pip-egg-info/psycopg2.egg-info/SOURCES.txt'
      warning: manifest_maker: standard file '-c' not found

      Error: pg_config executable not found.

      Please add the directory containing pg_config to the PATH
      or specify the full executable path with the option:

          python setup.py build_ext --pg-config /path/to/pg_config build ...

      or with the pg_config option in 'setup.cfg'.

      ----------------------------------------
  Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-z20gvx7_/psycopg2
  2015-11-16 21:03:27,010 ERROR    Error installing dependencies: Command '/opt/python/run/venv/bin/pip install -r /opt/python/ondeck/app/requirements.txt' returned non-zero exit status 1
  Traceback (most recent call last):
    File "/opt/elasticbeanstalk/hooks/appdeploy/pre/03deploy.py", line 22, in main
      install_dependencies()
    File "/opt/elasticbeanstalk/hooks/appdeploy/pre/03deploy.py", line 18, in install_dependencies
      check_call('%s install -r %s' % (os.path.join(APP_VIRTUAL_ENV, 'bin', 'pip'), requirements_file), shell=True)
    File "/usr/lib64/python2.7/subprocess.py", line 540, in check_call
      raise CalledProcessError(retcode, cmd)
  CalledProcessError: Command '/opt/python/run/venv/bin/pip install -r /opt/python/ondeck/app/requirements.txt' returned non-zero exit status 1 (ElasticBeanstalk::ExternalInvocationError)
caused by: Collecting psycopg2==2.6.1 (from -r /opt/python/ondeck/app/requirements.txt (line 1))
    Using cached psycopg2-2.6.1.tar.gz
      Complete output from command python setup.py egg_info:
      running egg_info
      creating pip-egg-info/psycopg2.egg-info
      writing top-level names to pip-egg-info/psycopg2.egg-info/top_level.txt
      writing dependency_links to pip-egg-info/psycopg2.egg-info/dependency_links.txt
      writing pip-egg-info/psycopg2.egg-info/PKG-INFO
      writing manifest file 'pip-egg-info/psycopg2.egg-info/SOURCES.txt'
      warning: manifest_maker: standard file '-c' not found

      Error: pg_config executable not found.

      Please add the directory containing pg_config to the PATH
      or specify the full executable path with the option:

          python setup.py build_ext --pg-config /path/to/pg_config build ...

      or with the pg_config option in 'setup.cfg'.

      ----------------------------------------
  Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-z20gvx7_/psycopg2
  2015-11-16 21:03:27,010 ERROR    Error installing dependencies: Command '/opt/python/run/venv/bin/pip install -r /opt/python/ondeck/app/requirements.txt' returned non-zero exit status 1
  Traceback (most recent call last):
    File "/opt/elasticbeanstalk/hooks/appdeploy/pre/03deploy.py", line 22, in main
      install_dependencies()
    File "/opt/elasticbeanstalk/hooks/appdeploy/pre/03deploy.py", line 18, in install_dependencies
      check_call('%s install -r %s' % (os.path.join(APP_VIRTUAL_ENV, 'bin', 'pip'), requirements_file), shell=True)
    File "/usr/lib64/python2.7/subprocess.py", line 540, in check_call
      raise CalledProcessError(retcode, cmd)
  CalledProcessError: Command '/opt/python/run/venv/bin/pip install -r /opt/python/ondeck/app/requirements.txt' returned non-zero exit status 1 (Executor::NonZeroExitStatus)

那样,字段数和mysql数总是一样的,因为它看是否有选择,那么如果它没有为你设置一个。

答案 1 :(得分:0)

从一个快速示例开始,假设您有这些表字段

$table_fields = array('foo', 'bar', 'baz');

您输入的数据如下所示

$input_data = array('foo' => 1,
                    'bar' => 2);

你可以做的是为每个表字段设置一些默认输入数据(我很懒,所以默认为NULL

array_fill(0, count($table_fields), NULL)

然后我们将它们与array_combine

一起压缩
array_combine($table_fields, array_fill(0, count($table_fields), NULL))

这样您的输入数据可以使用array_merge覆盖默认值,如下所示

var_dump(
    array_merge(
        array_combine($table_fields, array_fill(0, count($table_fields), NULL)),
        $input_data
    )
);

# prints
# array(3) {
#  ["foo"]=>
#  int(1)
#  ["bar"]=>
#  int(2)
#  ["baz"]=>
#  NULL
#}

但是,如果可能,您是否可以尝试将可选字段设为可选字段,以便在CREATE TABLE语句中确保为这些字段设置了默认值?在这种情况下,您还将保存一轮到数据库以查询字段名称($stmt->prepare("SELECT * FROM ".$db);,如果您确实需要,可能可以使用LIMIT 1来加速它。所以改为你的这一行

$ins = "INSERT INTO MYDB (".$fields.") VALUES (".$placeholders.")";

将成为

$ins = "INSERT INTO MYDB (".implode(",", array_keys($params)).") VALUES (".$placeholders.")";