【问题标题】:how to update foreign key in many to many relationship如何在多对多关系中更新外键
【发布时间】:2013-11-20 16:16:03
【问题描述】:

我是 php 新手,我有 2 个包含多对多关系的表和另一个用于关系的表:

每次我想更新外部表时都会报错:

Cannot add or update a child row: a foreign key constraint fails (`wikiseda`.`genre_singer`, CONSTRAINT `genre_singer_ibfk_1` FOREIGN KEY (`f_singer_id`) REFERENCES `singers` (`singerid`) ON DELETE CASCADE ON UPDATE CASCADE);

这是我的代码:

<?php
include('../db_inc.php');
define("UPLOAD_DIR",realpath(dirname(__FILE__)));

$singer_name =$_POST['singer_name'];
$singer_gender=$_POST['singer_gender'];
$singer_des=$_POST['singer_description'];
$singer_genre=$_POST['genre_list'];

    $path = UPLOAD_DIR .'/musics/'.$singer_name;
    if(!file_exists($path)){
        mkdir($path,0777,true);
        }

$sql ="INSERT INTO singers(singer_name,singer_gender,singer_description) VALUES ('$singer_name','$singer_gender','$singer_des')" ;
 $singer_id = mysql_insert_id();
$sql2 =("INSERT INTO genre_singer(f_singer_id,f_genre_id) VALUES ('$singer_id','$singer_genre')");

$result=mysql_query($sql)or die(mysql_error());
$result2=mysql_query($sql2)or die(mysql_error());
if('$result'){
    echo "insert successfully"; 

    };
?>

【问题讨论】:

  • 请切换到prepared statements以防止SQL injection
  • 没关系,但我的问题是另一回事
  • 你确实有一个不同的错误,是的,但这并不好。 mysql_ 函数已被弃用,您的代码容易受到 sql 注入的影响。这是一个比你的小 sql 错误更严重的问题。
  • 对于错误本身,请确保在执行查询之前您具有有效的 $singer_id 和 $singer_genre。它们必须是分别对应于歌手和流派表中的行 ID 的数值。
  • SQL 注入很糟糕,很常见但很糟糕......但我认为我以前从未见过 mkdir() 将 0777 权限嵌入到 PHP 中,这是一个新的可怕水平 - 希望是Apache/PHP 用户甚至没有权限执行此操作...尤其是因为它似乎正在 Web 树中创建一个目录。

标签: php mysql


【解决方案1】:

SQL 注入漏洞和过于宽松的目录权限暂时搁置一旁(尽管您真的应该注意这些问题的 cmets)。在尝试获取最后插入的 id 之前尝试执行您的第一个查询:

$sql ="INSERT INTO singers(singer_name,singer_gender,singer_description) VALUES ('$singer_name','$singer_gender','$singer_des')" ;    
$result=mysql_query($sql)or die(mysql_error());

$singer_id = mysql_insert_id();
$sql2 =("INSERT INTO genre_singer(f_singer_id,f_genre_id) VALUES ('$singer_id','$singer_genre')");
$result2=mysql_query($sql2)or die(mysql_error());

【讨论】:

    【解决方案2】:

    您试图在实际插入之前获取插入记录的 id。

    您需要将您的第一个查询执行 - $result=mysql_query($sql)or die(mysql_error()); 移到 $singer_id = mysql_insert_id(); 之前。

    还有:

    1. 您的代码容易受到 SQL 注入的攻击(正如其他人指出的那样)。

    2. 在服务器上使用来自用户的任意路径/名称创建目录可能是个坏主意。如果您随后以类似的方式创建文件,您将允许任何用户在您的服务器上执行任意代码。

    【讨论】:

    • 你能给我一篇关于在服务器上创建路径的正确方法的文章吗?
    • 在这种情况下我通常做的是只允许文件/目录名称的一小部分安全字符(例如a-zA-Z0-9 _-.)并且只允许特定的扩展名。 This question 看起来与使用用户提供的名称创建文件相关。
    【解决方案3】:

    为了完整起见,以下是使用 PDO 完成的工作:

    // note: untested code follows
    $pdo = new PDO('mysql:host='.$host.';dbname='.$db_name, $username, $password);
    
    $statement = $pdo->prepare('
        INSERT INTO `singers` (
            singer_name,
            singer_gender,
            singer_description
        ) VALUES (
            :singer_name,
            :singer_gender,
            :singer_des
        )
    ');
    
    $statement->execute(array(
        'singer_name'=>$_POST['singer_name'],
        'singer_gender'=>$_POST['singer_gender'],
        'singer_des'=>$_POST['singer_description']
    ));
    $singer_id = $pdo->lastInsertId();
    
    if (!$singer_id) {
        // tip: do something nicer than die
        die('Error occurred:'.implode(":",$pdo->errorInfo()));
    }
    
    
    $statement = $pdo->prepare('
        INSERT INTO `genre_singer` (
            f_singer_id,
            f_genre_id
        ) VALUES (
            :singer_id,
            :singer_genre
        )
    ');
    $result = $statement->execute(array(
        'singer_id'=>$singer_id,
        'singer_genre'=>$_POST['genre_list']
    ));
    
    if (!result) {
        // tip: do something nicer than die
        die('Error occurred:'.implode(":",$pdo->errorInfo()));
    }
    

    文档

    【讨论】:

    • 你没有忘记singer_id之前的$(在第二个execute语句中)吗?
    • @MarcelKorpel 是的,已修复。您可以编辑答案以修复此类问题:)
    • 我知道,只是不确定。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-30
    • 2020-06-07
    • 1970-01-01
    • 1970-01-01
    • 2019-08-25
    • 1970-01-01
    相关资源
    最近更新 更多